001 /* 002 * Copyright 2005-2008 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.rice.kns.service.impl; 017 018 import java.beans.PropertyDescriptor; 019 import java.lang.reflect.Field; 020 import java.lang.reflect.InvocationTargetException; 021 import java.util.HashSet; 022 import java.util.Iterator; 023 import java.util.List; 024 import java.util.Map; 025 import java.util.Set; 026 027 import org.apache.commons.beanutils.PropertyUtils; 028 import org.apache.commons.lang.StringUtils; 029 import org.apache.log4j.Logger; 030 import org.kuali.rice.core.jpa.metadata.EntityDescriptor; 031 import org.kuali.rice.core.jpa.metadata.MetadataManager; 032 import org.kuali.rice.core.jpa.metadata.ObjectDescriptor; 033 import org.kuali.rice.kns.bo.PersistableBusinessObject; 034 import org.kuali.rice.kns.dao.PersistenceDao; 035 import org.kuali.rice.kns.exception.IntrospectionException; 036 import org.kuali.rice.kns.exception.ObjectNotABusinessObjectRuntimeException; 037 import org.kuali.rice.kns.exception.ReferenceAttributeDoesntExistException; 038 import org.kuali.rice.kns.exception.ReferenceAttributeNotAnOjbReferenceException; 039 import org.kuali.rice.kns.service.PersistenceService; 040 import org.kuali.rice.kns.util.ObjectUtils; 041 import org.springframework.transaction.annotation.Transactional; 042 043 044 /** 045 * This class is the service implementation for the Persistence structure. 046 */ 047 @Transactional 048 public class PersistenceServiceJpaImpl extends PersistenceServiceImplBase implements PersistenceService { 049 050 private static Logger LOG = Logger.getLogger(PersistenceServiceJpaImpl.class); 051 private PersistenceDao persistenceDao; 052 053 public void setPersistenceDao(PersistenceDao persistenceDao) { 054 this.persistenceDao = persistenceDao; 055 } 056 057 /** 058 * @see org.kuali.rice.kns.service.PersistenceService#allForeignKeyValuesPopulatedForReference(org.kuali.rice.kns.bo.PersistableBusinessObject, java.lang.String) 059 */ 060 public boolean allForeignKeyValuesPopulatedForReference(PersistableBusinessObject bo, String referenceName) { 061 boolean allFkeysHaveValues = true; 062 063 // yelp if nulls were passed in 064 if (bo == null) { 065 throw new IllegalArgumentException("The Class passed in for the BusinessObject argument was null."); 066 } 067 if (StringUtils.isBlank(referenceName)) { 068 throw new IllegalArgumentException("The String passed in for the referenceName argument was null or empty."); 069 } 070 071 PropertyDescriptor propertyDescriptor = null; 072 073 // make sure the attribute exists at all, throw exception if not 074 try { 075 propertyDescriptor = PropertyUtils.getPropertyDescriptor(bo, referenceName); 076 } catch (Exception e) { 077 throw new RuntimeException(e); 078 } 079 if (propertyDescriptor == null) { 080 throw new ReferenceAttributeDoesntExistException("Requested attribute: '" + referenceName + "' does not exist " + "on class: '" + bo.getClass().getName() + "'."); 081 } 082 083 // get the class of the attribute name 084 Class referenceClass = getBusinessObjectAttributeClass( bo.getClass(), referenceName ); 085 if ( referenceClass == null ) { 086 referenceClass = propertyDescriptor.getPropertyType(); 087 } 088 089 // make sure the class of the attribute descends from BusinessObject, 090 // otherwise throw an exception 091 if (!PersistableBusinessObject.class.isAssignableFrom(referenceClass)) { 092 throw new ObjectNotABusinessObjectRuntimeException("Attribute requested (" + referenceName + ") is of class: " + "'" + referenceClass.getName() + "' and is not a " + "descendent of BusinessObject. Only descendents of BusinessObject " + "can be used."); 093 } 094 095 EntityDescriptor descriptor = MetadataManager.getEntityDescriptor(bo.getClass()); 096 ObjectDescriptor objectDescriptor = descriptor.getObjectDescriptorByName(referenceName); 097 if (objectDescriptor == null) { 098 throw new ReferenceAttributeNotAnOjbReferenceException("Attribute requested (" + referenceName + ") is not listed " + "in OJB as a reference-descriptor for class: '" + bo.getClass().getName() + "'"); 099 } 100 101 // get the list of the foreign-keys for this reference-descriptor 102 List fkFields = objectDescriptor.getForeignKeyFields(); 103 Iterator fkIterator = fkFields.iterator(); 104 105 // walk through the list of the foreign keys, get their types 106 while (fkIterator.hasNext()) { 107 108 // get the field name of the fk & pk field 109 String fkFieldName = (String) fkIterator.next(); 110 111 // get the value for the fk field 112 Object fkFieldValue = null; 113 try { 114 fkFieldValue = PropertyUtils.getSimpleProperty(bo, fkFieldName); 115 } 116 117 // if we cant retrieve the field value, then 118 // it doesnt have a value 119 catch (IllegalAccessException e) { 120 return false; 121 } catch (InvocationTargetException e) { 122 return false; 123 } catch (NoSuchMethodException e) { 124 return false; 125 } 126 127 // test the value 128 if (fkFieldValue == null) { 129 return false; 130 } else if (String.class.isAssignableFrom(fkFieldValue.getClass())) { 131 if (StringUtils.isBlank((String) fkFieldValue)) { 132 return false; 133 } 134 } 135 } 136 137 return allFkeysHaveValues; 138 } 139 140 /** 141 * @see org.kuali.rice.kns.service.PersistenceService#clearCache() 142 */ 143 public void clearCache() { 144 persistenceDao.clearCache(); 145 } 146 147 /** 148 * @see org.kuali.rice.kns.service.PersistenceService#getFlattenedPrimaryKeyFieldValues(java.lang.Object) 149 */ 150 public String getFlattenedPrimaryKeyFieldValues(Object persistableObject) { 151 if (persistableObject == null) { 152 throw new IllegalArgumentException("invalid (null) persistableObject"); 153 } 154 155 Map primaryKeyValues = getPrimaryKeyFieldValues(persistableObject, true); 156 157 StringBuffer flattened = new StringBuffer(persistableObject.getClass().getName()); 158 flattened.append("("); 159 for (Iterator i = primaryKeyValues.entrySet().iterator(); i.hasNext();) { 160 Map.Entry e = (Map.Entry) i.next(); 161 162 String fieldName = (String) e.getKey(); 163 Object fieldValue = e.getValue(); 164 165 flattened.append(fieldName + "=" + fieldValue); 166 if (i.hasNext()) { 167 flattened.append(","); 168 } 169 } 170 171 flattened.append(")"); 172 173 return flattened.toString(); 174 } 175 176 /** 177 * @see org.kuali.rice.kns.service.PersistenceService#linkObjects(java.lang.Object) 178 */ 179 public void linkObjects(Object persistableObject) { 180 linkObjectsWithCircularReferenceCheck(persistableObject, new HashSet()); 181 } 182 183 /** 184 * @see org.kuali.rice.kns.service.PersistenceService#loadRepositoryDescriptor(java.lang.String) 185 */ 186 public void loadRepositoryDescriptor(String ojbRepositoryFilePath) {} 187 188 /** 189 * @see org.kuali.rice.kns.service.PersistenceService#refreshAllNonUpdatingReferences(org.kuali.rice.kns.bo.PersistableBusinessObject) 190 */ 191 public void refreshAllNonUpdatingReferences(PersistableBusinessObject bo) { 192 EntityDescriptor descriptor = MetadataManager.getEntityDescriptor(bo.getClass()); 193 List<ObjectDescriptor> objectDescriptors = descriptor.getObjectRelationships(); 194 195 for (ObjectDescriptor od : objectDescriptors) { 196 if (od.getCascade().length == 0) { 197 retrieveReferenceObject(bo, od.getAttributeName()); 198 } 199 } 200 } 201 202 /** 203 * @see org.kuali.rice.kns.service.PersistenceService#resolveProxy(java.lang.Object) 204 */ 205 public Object resolveProxy(Object o) { 206 return persistenceDao.resolveProxy(o); 207 } 208 209 /** 210 * @see org.kuali.rice.kns.service.PersistenceService#retrieveNonKeyFields(java.lang.Object) 211 */ 212 public void retrieveNonKeyFields(Object persistableObject) { 213 if (persistableObject == null) { 214 throw new IllegalArgumentException("invalid (null) persistableObject"); 215 } 216 LOG.debug("retrieving non-key fields for " + persistableObject); 217 218 persistenceDao.retrieveAllReferences(persistableObject); 219 } 220 221 /** 222 * @see org.kuali.rice.kns.service.PersistenceService#retrieveReferenceObject(java.lang.Object, java.lang.String) 223 */ 224 public void retrieveReferenceObject(Object persistableObject, String referenceObjectName) { 225 if (persistableObject == null) { 226 throw new IllegalArgumentException("invalid (null) persistableObject"); 227 } 228 LOG.debug("retrieving reference object " + referenceObjectName + " for " + persistableObject); 229 230 persistenceDao.retrieveReference(persistableObject, referenceObjectName); 231 } 232 233 /** 234 * @see org.kuali.rice.kns.service.PersistenceService#retrieveReferenceObjects(java.lang.Object, java.util.List) 235 */ 236 public void retrieveReferenceObjects(Object persistableObject, List referenceObjectNames) { 237 if (persistableObject == null) { 238 throw new IllegalArgumentException("invalid (null) persistableObject"); 239 } 240 if (referenceObjectNames == null) { 241 throw new IllegalArgumentException("invalid (null) referenceObjectNames"); 242 } 243 if (referenceObjectNames.isEmpty()) { 244 throw new IllegalArgumentException("invalid (empty) referenceObjectNames"); 245 } 246 247 int index = 0; 248 for (Iterator i = referenceObjectNames.iterator(); i.hasNext(); index++) { 249 String referenceObjectName = (String) i.next(); 250 if (StringUtils.isBlank(referenceObjectName)) { 251 throw new IllegalArgumentException("invalid (blank) name at position " + index); 252 } 253 254 retrieveReferenceObject(persistableObject, referenceObjectName); 255 } 256 } 257 258 /** 259 * @see org.kuali.rice.kns.service.PersistenceService#retrieveReferenceObjects(java.util.List, java.util.List) 260 */ 261 public void retrieveReferenceObjects(List persistableObjects, List referenceObjectNames) { 262 if (persistableObjects == null) { 263 throw new IllegalArgumentException("invalid (null) persistableObjects"); 264 } 265 if (persistableObjects.isEmpty()) { 266 throw new IllegalArgumentException("invalid (empty) persistableObjects"); 267 } 268 if (referenceObjectNames == null) { 269 throw new IllegalArgumentException("invalid (null) referenceObjectNames"); 270 } 271 if (referenceObjectNames.isEmpty()) { 272 throw new IllegalArgumentException("invalid (empty) referenceObjectNames"); 273 } 274 275 for (Iterator i = persistableObjects.iterator(); i.hasNext();) { 276 Object persistableObject = i.next(); 277 retrieveReferenceObjects(persistableObject, referenceObjectNames); 278 } 279 } 280 281 private void linkObjectsWithCircularReferenceCheck(Object persistableObject, Set referenceSet) { 282 if (ObjectUtils.isNull(persistableObject) || referenceSet.contains(persistableObject)) { 283 return; 284 } 285 286 referenceSet.add(persistableObject); 287 288 EntityDescriptor descriptor = MetadataManager.getEntityDescriptor(persistableObject.getClass()); 289 290 String className = null; 291 String fieldName = null; 292 try { 293 // iterate through all object references for the persistableObject 294 List<ObjectDescriptor> objectDescriptors = descriptor.getObjectRelationships(); 295 for (ObjectDescriptor od : objectDescriptors) { 296 // get the actual reference object 297 className = persistableObject.getClass().getName(); 298 fieldName = od.getAttributeName(); 299 Object referenceObject = PropertyUtils.getProperty(persistableObject, fieldName); 300 if (ObjectUtils.isNull(referenceObject) || referenceSet.contains(referenceObject)) { 301 continue; 302 } 303 304 // recursively link object 305 linkObjectsWithCircularReferenceCheck(referenceObject, referenceSet); 306 307 // iterate through the keys for the reference object and set value 308 List<String> refFkNames = od.getForeignKeyFields(); 309 EntityDescriptor refCld = MetadataManager.getEntityDescriptor(od.getTargetEntity()); 310 Set<org.kuali.rice.core.jpa.metadata.FieldDescriptor> refPkNames = refCld.getPrimaryKeys(); 311 312 try { 313 for (String fk : refFkNames) { 314 Field f = referenceObject.getClass().getDeclaredField(fk); 315 f.setAccessible(true); 316 if (ObjectUtils.isNull(f.get(referenceObject))) { 317 Field f2 = persistableObject.getClass().getDeclaredField(fk); 318 f2.setAccessible(true); 319 f.set(referenceObject, f2.get(persistableObject)); 320 } 321 } 322 } catch (Exception e) { 323 LOG.error(e.getMessage(), e); 324 } 325 } 326 } catch (NoSuchMethodException e) { 327 throw new IntrospectionException("no setter for property '" + className + "." + fieldName + "'", e); 328 } catch (IllegalAccessException e) { 329 throw new IntrospectionException("problem accessing property '" + className + "." + fieldName + "'", e); 330 } catch (InvocationTargetException e) { 331 throw new IntrospectionException("problem invoking getter for property '" + className + "." + fieldName + "'", e); 332 } 333 } 334 335 }