001: /*
002: * Copyright 2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.module.purap.util;
017:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: import org.kuali.core.bo.PersistableBusinessObject;
024: import org.kuali.core.util.ObjectUtils;
025: import org.kuali.core.util.OjbCollectionAware;
026: import org.springframework.orm.ObjectRetrievalFailureException;
027:
028: /**
029: * Helper object to deal with persisting collections.
030: */
031: public class PurApOjbCollectionHelper {
032: public final static int MAX_DEPTH = 2;
033:
034: /**
035: * OJB RemovalAwareLists do not survive through the response/request lifecycle. This method is a work-around to forcibly remove
036: * business objects that are found in Collections stored in the database but not in memory.
037: *
038: * @param orig
039: * @param id
040: * @param template
041: */
042: public void processCollections(OjbCollectionAware template,
043: PersistableBusinessObject orig,
044: PersistableBusinessObject copy) {
045: processCollectionsRecurse(template, orig, copy, MAX_DEPTH);
046: }
047:
048: /**
049: * This method processes collections recursively up to the depth level specified
050: *
051: * @param template
052: * @param orig
053: * @param copy
054: */
055: private void processCollectionsRecurse(OjbCollectionAware template,
056: PersistableBusinessObject orig,
057: PersistableBusinessObject copy, int depth) {
058: if (copy == null || depth < 1) {
059: return;
060: }
061:
062: List originalCollections = orig.buildListOfDeletionAwareLists();
063:
064: if (originalCollections != null
065: && !originalCollections.isEmpty()) {
066: /*
067: * Prior to being saved, the version in the database will not yet reflect any deleted collections. So, a freshly
068: * retrieved version will contain objects that need to be removed:
069: */
070: try {
071: List copyCollections = copy
072: .buildListOfDeletionAwareLists();
073: int size = originalCollections.size();
074:
075: if (copyCollections.size() != size) {
076: throw new RuntimeException(
077: "size mismatch while attempting to process list of Collections to manage");
078: }
079:
080: for (int i = 0; i < size; i++) {
081: Collection<PersistableBusinessObject> origSource = (Collection<PersistableBusinessObject>) originalCollections
082: .get(i);
083: Collection<PersistableBusinessObject> copySource = (Collection<PersistableBusinessObject>) copyCollections
084: .get(i);
085: List list = findUnwantedElements(copySource,
086: origSource, template, depth - 1);
087: cleanse(template, origSource, list);
088:
089: }
090: } catch (ObjectRetrievalFailureException orfe) {
091: // object wasn't found, must be pre-save
092: }
093: }
094: }
095:
096: /**
097: * OJB RemovalAwareLists do not survive through the response/request lifecycle. This method is a work-around to forcibly remove
098: * business objects that are found in Collections stored in the database but not in memory.
099: *
100: * @param orig
101: * @param id
102: * @param template
103: */
104: public void processCollections2(OjbCollectionAware template,
105: PersistableBusinessObject orig,
106: PersistableBusinessObject copy) {
107: // if copy is null this is the first time we are saving the object, don't have to worry about updating collections
108: if (copy == null) {
109: return;
110: }
111:
112: List originalCollections = orig.buildListOfDeletionAwareLists();
113:
114: if (originalCollections != null
115: && !originalCollections.isEmpty()) {
116: /*
117: * Prior to being saved, the version in the database will not yet reflect any deleted collections. So, a freshly
118: * retrieved version will contain objects that need to be removed:
119: */
120: try {
121: List copyCollections = copy
122: .buildListOfDeletionAwareLists();
123: int size = originalCollections.size();
124:
125: if (copyCollections.size() != size) {
126: throw new RuntimeException(
127: "size mismatch while attempting to process list of Collections to manage");
128: }
129:
130: for (int i = 0; i < size; i++) {
131: Collection origSource = (Collection) originalCollections
132: .get(i);
133: Collection copySource = (Collection) copyCollections
134: .get(i);
135: List list = findUnwantedElements(copySource,
136: origSource, null, 0);
137: cleanse(template, origSource, list);
138:
139: }
140: } catch (ObjectRetrievalFailureException orfe) {
141: // object wasn't found, must be pre-save
142: }
143: }
144: }
145:
146: /**
147: * This method deletes unwanted objects from the database as well as from the given input List
148: *
149: * @param origSource - list containing unwanted business objects
150: * @param unwantedItems - business objects to be permanently removed
151: * @param template
152: */
153: private void cleanse(OjbCollectionAware template,
154: Collection origSource, List unwantedItems) {
155: if (unwantedItems.size() > 0) {
156: Iterator iter = unwantedItems.iterator();
157: while (iter.hasNext()) {
158: template.getPersistenceBrokerTemplate().delete(
159: iter.next());
160: }
161: }
162:
163: }
164:
165: /**
166: * This method identifies items in the first List that are not contained in the second List. It is similar to the (optional)
167: * java.util.List retainAll method.
168: *
169: * @param fromList list from the database
170: * @param controlList list from the object
171: * @return true iff one or more items were removed
172: */
173: private List findUnwantedElements(Collection fromList,
174: Collection controlList, OjbCollectionAware template,
175: int depth) {
176: List toRemove = new ArrayList();
177:
178: Iterator iter = fromList.iterator();
179: while (iter.hasNext()) {
180: PersistableBusinessObject copyLine = (PersistableBusinessObject) iter
181: .next();
182:
183: PersistableBusinessObject line = (PersistableBusinessObject) PurApObjectUtils
184: .retrieveObjectWithIdentitcalKey(controlList,
185: copyLine);
186: if (ObjectUtils.isNull(line)) {
187: toRemove.add(copyLine);
188: } else { // since we're not deleting try to recurse on this element
189: processCollectionsRecurse(template, line, copyLine,
190: depth);
191: }
192: }
193: return toRemove;
194: }
195: }
|