View Javadoc
1   /*
2    * Copyright 2007 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.ole.module.purap.util;
17  
18  import org.kuali.rice.krad.bo.PersistableBusinessObject;
19  import org.kuali.rice.krad.service.util.OjbCollectionAware;
20  import org.kuali.rice.krad.util.ObjectUtils;
21  import org.springframework.orm.ObjectRetrievalFailureException;
22  
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Iterator;
26  import java.util.List;
27  
28  /**
29   * Helper object to deal with persisting collections.
30   */
31  public class PurApOjbCollectionHelper {
32      public final static int MAX_DEPTH = 2;
33  
34      /**
35       * OJB RemovalAwareLists do not survive through the response/request lifecycle. This method is a work-around to forcibly remove
36       * business objects that are found in Collections stored in the database but not in memory.
37       *
38       * @param orig
39       * @param id
40       * @param template
41       */
42      public void processCollections(OjbCollectionAware template, PersistableBusinessObject orig, PersistableBusinessObject copy) {
43          processCollectionsRecurse(template, orig, copy, MAX_DEPTH);
44      }
45  
46      /**
47       * This method processes collections recursively up to the depth level specified
48       *
49       * @param template
50       * @param orig
51       * @param copy
52       */
53      private void processCollectionsRecurse(OjbCollectionAware template, PersistableBusinessObject orig, PersistableBusinessObject copy, int depth) {
54          if (copy == null || depth < 1) {
55              return;
56          }
57  
58          List originalCollections = orig.buildListOfDeletionAwareLists();
59  
60          if (originalCollections != null && !originalCollections.isEmpty()) {
61              /*
62               * Prior to being saved, the version in the database will not yet reflect any deleted collections. So, a freshly
63               * retrieved version will contain objects that need to be removed:
64               */
65              try {
66                  List copyCollections = copy.buildListOfDeletionAwareLists();
67                  int size = originalCollections.size();
68  
69                  if (copyCollections.size() != size) {
70                      throw new RuntimeException("size mismatch while attempting to process list of Collections to manage");
71                  }
72  
73                  for (int i = 0; i < size; i++) {
74                      Collection<PersistableBusinessObject> origSource = (Collection<PersistableBusinessObject>) originalCollections.get(i);
75                      Collection<PersistableBusinessObject> copySource = (Collection<PersistableBusinessObject>) copyCollections.get(i);
76                      List list = findUnwantedElements(copySource, origSource, template, depth - 1);
77                      cleanse(template, origSource, list);
78  
79                  }
80              } catch (ObjectRetrievalFailureException orfe) {
81                  // object wasn't found, must be pre-save
82              }
83          }
84      }
85  
86      /**
87       * OJB RemovalAwareLists do not survive through the response/request lifecycle. This method is a work-around to forcibly remove
88       * business objects that are found in Collections stored in the database but not in memory.
89       *
90       * @param orig
91       * @param id
92       * @param template
93       */
94      public void processCollections2(OjbCollectionAware template, PersistableBusinessObject orig, PersistableBusinessObject copy) {
95          // if copy is null this is the first time we are saving the object, don't have to worry about updating collections
96          if (copy == null) {
97              return;
98          }
99  
100         List originalCollections = orig.buildListOfDeletionAwareLists();
101 
102         if (originalCollections != null && !originalCollections.isEmpty()) {
103             /*
104              * Prior to being saved, the version in the database will not yet reflect any deleted collections. So, a freshly
105              * retrieved version will contain objects that need to be removed:
106              */
107             try {
108                 List copyCollections = copy.buildListOfDeletionAwareLists();
109                 int size = originalCollections.size();
110 
111                 if (copyCollections.size() != size) {
112                     throw new RuntimeException("size mismatch while attempting to process list of Collections to manage");
113                 }
114 
115                 for (int i = 0; i < size; i++) {
116                     Collection origSource = (Collection) originalCollections.get(i);
117                     Collection copySource = (Collection) copyCollections.get(i);
118                     List list = findUnwantedElements(copySource, origSource, null, 0);
119                     cleanse(template, origSource, list);
120 
121                 }
122             } catch (ObjectRetrievalFailureException orfe) {
123                 // object wasn't found, must be pre-save
124             }
125         }
126     }
127 
128     /**
129      * This method deletes unwanted objects from the database as well as from the given input List
130      *
131      * @param origSource    - list containing unwanted business objects
132      * @param unwantedItems - business objects to be permanently removed
133      * @param template
134      */
135     private void cleanse(OjbCollectionAware template, Collection origSource, List unwantedItems) {
136         if (unwantedItems.size() > 0) {
137             Iterator iter = unwantedItems.iterator();
138             while (iter.hasNext()) {
139                 template.getPersistenceBrokerTemplate().delete(iter.next());
140             }
141         }
142 
143     }
144 
145     /**
146      * This method identifies items in the first List that are not contained in the second List. It is similar to the (optional)
147      * java.util.List retainAll method.
148      *
149      * @param fromList    list from the database
150      * @param controlList list from the object
151      * @return true iff one or more items were removed
152      */
153     private List findUnwantedElements(Collection fromList, Collection controlList, OjbCollectionAware template, int depth) {
154         List toRemove = new ArrayList();
155 
156         Iterator iter = fromList.iterator();
157         while (iter.hasNext()) {
158             PersistableBusinessObject copyLine = (PersistableBusinessObject) iter.next();
159 
160             PersistableBusinessObject line = (PersistableBusinessObject) PurApObjectUtils.retrieveObjectWithIdentitcalKey(controlList, copyLine);
161             if (ObjectUtils.isNull(line)) {
162                 toRemove.add(copyLine);
163             } else { // since we're not deleting try to recurse on this element
164                 processCollectionsRecurse(template, line, copyLine, depth);
165             }
166         }
167         return toRemove;
168     }
169 }