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