View Javadoc

1   /**
2    * Copyright 2005-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.service.impl;
17  
18  import java.beans.PropertyDescriptor;
19  import java.lang.reflect.Field;
20  import java.lang.reflect.InvocationTargetException;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  
27  import org.apache.commons.beanutils.PropertyUtils;
28  import org.apache.commons.lang.StringUtils;
29  import org.apache.log4j.Logger;
30  import org.kuali.rice.core.framework.persistence.jpa.metadata.EntityDescriptor;
31  import org.kuali.rice.core.framework.persistence.jpa.metadata.MetadataManager;
32  import org.kuali.rice.core.framework.persistence.jpa.metadata.ObjectDescriptor;
33  import org.kuali.rice.krad.bo.PersistableBusinessObject;
34  import org.kuali.rice.krad.dao.PersistenceDao;
35  import org.kuali.rice.krad.exception.IntrospectionException;
36  import org.kuali.rice.krad.exception.ObjectNotABusinessObjectRuntimeException;
37  import org.kuali.rice.krad.exception.ReferenceAttributeDoesntExistException;
38  import org.kuali.rice.krad.exception.ReferenceAttributeNotAnOjbReferenceException;
39  import org.kuali.rice.krad.service.PersistenceService;
40  import org.kuali.rice.krad.util.ObjectUtils;
41  import org.springframework.transaction.annotation.Transactional;
42  
43  
44  /**
45   * This class is the service implementation for the Persistence structure.
46   */
47  @Transactional
48  public class PersistenceServiceJpaImpl extends PersistenceServiceImplBase implements PersistenceService {
49  
50  	private static Logger LOG = Logger.getLogger(PersistenceServiceJpaImpl.class);
51      private PersistenceDao persistenceDao;
52          
53      public void setPersistenceDao(PersistenceDao persistenceDao) {
54          this.persistenceDao = persistenceDao;
55      }
56  
57  	/**
58  	 * @see org.kuali.rice.krad.service.PersistenceService#allForeignKeyValuesPopulatedForReference(org.kuali.rice.krad.bo.PersistableBusinessObject, java.lang.String)
59  	 */
60  	public boolean allForeignKeyValuesPopulatedForReference(PersistableBusinessObject bo, String referenceName) {
61          boolean allFkeysHaveValues = true;
62  
63          // yelp if nulls were passed in
64          if (bo == null) {
65              throw new IllegalArgumentException("The Class passed in for the BusinessObject argument was null.");
66          }
67          if (StringUtils.isBlank(referenceName)) {
68              throw new IllegalArgumentException("The String passed in for the referenceName argument was null or empty.");
69          }
70  
71          PropertyDescriptor propertyDescriptor = null;
72  
73          // make sure the attribute exists at all, throw exception if not
74          try {
75              propertyDescriptor = PropertyUtils.getPropertyDescriptor(bo, referenceName);
76  		} catch (Exception e) {
77              throw new RuntimeException(e);
78          }
79          if (propertyDescriptor == null) {
80              throw new ReferenceAttributeDoesntExistException("Requested attribute: '" + referenceName + "' does not exist " + "on class: '" + bo.getClass().getName() + "'.");
81          }
82  
83          // get the class of the attribute name
84          Class referenceClass = getBusinessObjectAttributeClass( bo.getClass(), referenceName );
85          if ( referenceClass == null ) {
86          	referenceClass = propertyDescriptor.getPropertyType();
87          }
88  
89          // make sure the class of the attribute descends from BusinessObject,
90          // otherwise throw an exception
91          if (!PersistableBusinessObject.class.isAssignableFrom(referenceClass)) {
92  			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.");
93          }
94  
95          EntityDescriptor descriptor = MetadataManager.getEntityDescriptor(bo.getClass());
96      	ObjectDescriptor objectDescriptor = descriptor.getObjectDescriptorByName(referenceName);
97          if (objectDescriptor == null) {
98              throw new ReferenceAttributeNotAnOjbReferenceException("Attribute requested (" + referenceName + ") is not listed " + "in OJB as a reference-descriptor for class: '" + bo.getClass().getName() + "'");
99          }
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.krad.service.PersistenceService#clearCache()
142 	 */
143 	public void clearCache() {
144 		persistenceDao.clearCache();
145 	}
146 
147 	/**
148 	 * @see org.kuali.rice.krad.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.krad.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.krad.service.PersistenceService#loadRepositoryDescriptor(java.lang.String)
185 	 */
186 	public void loadRepositoryDescriptor(String ojbRepositoryFilePath) {}
187 
188 	/**
189 	 * @see org.kuali.rice.krad.service.PersistenceService#refreshAllNonUpdatingReferences(org.kuali.rice.krad.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.krad.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.krad.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.krad.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.krad.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.krad.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.framework.persistence.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     /**
336 	 * Asks persistenceDao if this represents a proxy
337 	 * 
338 	 * @see org.kuali.rice.krad.service.PersistenceService#isProxied(java.lang.Object)
339 	 */
340 	public boolean isProxied(Object object) {
341 		return persistenceDao.isProxied(object);
342 	}
343 }