001 /** 002 * Copyright 2005-2012 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.krad.util; 017 018 import java.util.ArrayList; 019 import java.util.Collection; 020 import java.util.List; 021 022 import org.apache.log4j.Logger; 023 import org.kuali.rice.krad.bo.PersistableBusinessObject; 024 import org.springframework.orm.ObjectRetrievalFailureException; 025 026 /** 027 * Helper object to deal with persisting collections. 028 */ 029 public class OjbCollectionHelper { 030 private static final Logger LOG = Logger.getLogger(OjbCollectionHelper.class); 031 /** 032 * OJB RemovalAwareLists do not survive through the response/request lifecycle. This method is a work-around to forcibly remove 033 * business objects that are found in Collections stored in the database but not in memory. 034 * 035 * @param orig 036 * @param id 037 * @param template 038 */ 039 public void processCollections(OjbCollectionAware template, PersistableBusinessObject orig, PersistableBusinessObject copy) { 040 if (copy == null) { 041 return; 042 } 043 044 List<Collection<PersistableBusinessObject>> originalCollections = orig.buildListOfDeletionAwareLists(); 045 046 if (originalCollections != null && !originalCollections.isEmpty()) { 047 /* 048 * Prior to being saved, the version in the database will not yet reflect any deleted collections. So, a freshly 049 * retrieved version will contain objects that need to be removed: 050 */ 051 try { 052 List<Collection<PersistableBusinessObject>> copyCollections = copy.buildListOfDeletionAwareLists(); 053 int size = originalCollections.size(); 054 055 if (copyCollections.size() != size) { 056 throw new RuntimeException("size mismatch while attempting to process list of Collections to manage"); 057 } 058 059 for (int i = 0; i < size; i++) { 060 Collection<PersistableBusinessObject> origSource = originalCollections.get(i); 061 Collection<PersistableBusinessObject> copySource = copyCollections.get(i); 062 List<PersistableBusinessObject> list = findUnwantedElements(copySource, origSource); 063 cleanse(template, origSource, list); 064 } 065 } 066 catch (ObjectRetrievalFailureException orfe) { 067 // object wasn't found, must be pre-save 068 } 069 } 070 } 071 072 /** 073 * OJB RemovalAwareLists do not survive through the response/request lifecycle. This method is a work-around to forcibly remove 074 * business objects that are found in Collections stored in the database but not in memory. 075 * 076 * @param orig 077 * @param id 078 * @param template 079 */ 080 public void processCollections2(OjbCollectionAware template, PersistableBusinessObject orig, PersistableBusinessObject copy) { 081 // if copy is null this is the first time we are saving the object, don't have to worry about updating collections 082 if (copy == null) { 083 return; 084 } 085 086 List<Collection<PersistableBusinessObject>> originalCollections = orig.buildListOfDeletionAwareLists(); 087 088 if (originalCollections != null && !originalCollections.isEmpty()) { 089 /* 090 * Prior to being saved, the version in the database will not yet reflect any deleted collections. So, a freshly 091 * retrieved version will contain objects that need to be removed: 092 */ 093 try { 094 List<Collection<PersistableBusinessObject>> copyCollections = copy.buildListOfDeletionAwareLists(); 095 int size = originalCollections.size(); 096 097 if (copyCollections.size() != size) { 098 throw new RuntimeException("size mismatch while attempting to process list of Collections to manage"); 099 } 100 101 for (int i = 0; i < size; i++) { 102 Collection<PersistableBusinessObject> origSource = originalCollections.get(i); 103 Collection<PersistableBusinessObject> copySource = copyCollections.get(i); 104 List<PersistableBusinessObject> list = findUnwantedElements(copySource, origSource); 105 cleanse(template, origSource, list); 106 } 107 } 108 catch (ObjectRetrievalFailureException orfe) { 109 // object wasn't found, must be pre-save 110 } 111 } 112 } 113 114 /** 115 * This method deletes unwanted objects from the database as well as from the given input List 116 * 117 * @param origSource - list containing unwanted business objects 118 * @param unwantedItems - business objects to be permanently removed 119 * @param template 120 */ 121 private void cleanse(OjbCollectionAware template, Collection<PersistableBusinessObject> origSource, List<PersistableBusinessObject> unwantedItems) { 122 if (unwantedItems.size() > 0) { 123 for (PersistableBusinessObject unwantedItem : unwantedItems) { 124 if ( LOG.isDebugEnabled() ) { 125 LOG.debug( "cleansing " + unwantedItem); 126 } 127 template.getPersistenceBrokerTemplate().delete(unwantedItem); 128 } 129 } 130 131 } 132 133 /** 134 * This method identifies items in the first List that are not contained in the second List. It is similar to the (optional) 135 * java.util.List retainAll method. 136 * 137 * @param fromList 138 * @param controlList 139 * @return true iff one or more items were removed 140 */ 141 private List<PersistableBusinessObject> findUnwantedElements(Collection<PersistableBusinessObject> fromList, Collection<PersistableBusinessObject> controlList) { 142 List<PersistableBusinessObject> toRemove = new ArrayList<PersistableBusinessObject>(); 143 144 for (PersistableBusinessObject fromObject : fromList) { 145 if (!ObjectUtils.collectionContainsObjectWithIdentitcalKey(controlList, fromObject)) { 146 toRemove.add(fromObject); 147 } 148 } 149 return toRemove; 150 } 151 }