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 }