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 }