001/** 002 * Copyright 2005-2015 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 */ 016package org.kuali.rice.krms.impl.ui; 017 018import org.apache.commons.collections.CollectionUtils; 019import org.kuali.rice.krad.maintenance.MaintainableImpl; 020import org.kuali.rice.krad.maintenance.MaintenanceDocument; 021import org.kuali.rice.krad.uif.util.ObjectPropertyUtils; 022import org.kuali.rice.krad.uif.view.ViewModel; 023import org.kuali.rice.krad.util.KRADConstants; 024import org.kuali.rice.krad.web.form.MaintenanceDocumentForm; 025import org.kuali.rice.krms.api.repository.context.ContextDefinition; 026import org.kuali.rice.krms.impl.repository.ContextBo; 027import org.kuali.rice.krms.impl.repository.ContextValidTermBo; 028import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator; 029import org.kuali.rice.krms.impl.repository.TermSpecificationBo; 030 031import java.util.ArrayList; 032import java.util.List; 033import java.util.ListIterator; 034import java.util.Map; 035 036/** 037 * {@link org.kuali.rice.krad.maintenance.Maintainable} for the {@link AgendaEditor} 038 * 039 * @author Kuali Rice Team (rice.collab@kuali.org) 040 * 041 */ 042public class TermSpecificationMaintainable extends MaintainableImpl { 043 044 private static final long serialVersionUID = 1L; 045 046 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(TermSpecificationMaintainable.class); 047 048 @Override 049 public Object retrieveObjectForEditOrCopy(MaintenanceDocument document, Map<String, String> dataObjectKeys) { 050 051 TermSpecificationBo termSpecificationBo = (TermSpecificationBo) super.retrieveObjectForEditOrCopy(document, 052 dataObjectKeys); 053 054 if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(getMaintenanceAction())) { 055 document.getDocumentHeader().setDocumentDescription("New Term Specification Document"); 056 } 057 058 return termSpecificationBo; 059 } 060 061 /** 062 * {@inheritDoc} 063 */ 064 @Override 065 public void processAfterNew(MaintenanceDocument document, 066 Map<String, String[]> requestParameters) { 067 068 super.processAfterNew(document, requestParameters); 069 document.getDocumentHeader().setDocumentDescription("New Term Specification Document"); 070 071 } 072 073 /** 074 * {@inheritDoc} 075 */ 076 @Override 077 public void processAfterEdit(MaintenanceDocument document, Map<String, String[]> requestParameters) { 078 super.processAfterEdit(document, requestParameters); 079 document.getDocumentHeader().setDocumentDescription("Edited Term Specification Document"); 080 } 081 082 @Override 083 public void processAfterCopy(MaintenanceDocument document, Map<String, String[]> requestParameters) { 084 super.processAfterCopy(document, requestParameters); 085 copyContextsOldToNewBo(document); 086 setNewContextValidTermsNewBO(document); 087 } 088 089 /** 090 * Copy the contexts from the old TermSpecificationBo to the newTermSpecificationBo of the maintenance document. 091 * <p> 092 * Since the contexts is a transient field it doesn't get copied by the deepCopy in 093 * MaintenanceDocumentServiceImpl.setupMaintenanceObject, we manually need to copy the values over. 094 * For performance reasons a shallow copy is done since the ContextBo themselves are never changed. 095 * </p> 096 * @param document that contains the old and new TermSpecificationBos 097 */ 098 private void copyContextsOldToNewBo(MaintenanceDocument document) { 099 TermSpecificationBo newTermSpec = (TermSpecificationBo) document.getNewMaintainableObject().getDataObject(); 100 101 // Hydrade contexts as they are transient 102 newTermSpec.getContexts().clear(); 103 newTermSpec.getContexts(); 104 } 105 106 private void setNewContextValidTermsNewBO(MaintenanceDocument document) { 107 TermSpecificationBo newTermSpec = (TermSpecificationBo) document.getNewMaintainableObject().getDataObject(); 108 for (ContextValidTermBo contextValidTermBo : newTermSpec.getContextValidTerms()) { 109 contextValidTermBo.setId(null); 110 contextValidTermBo.setTermSpecification(newTermSpec); 111 } 112 } 113 114 /** 115 * Overrides the parent method to additionaly clear the contexts list, which is needed for serialization performance 116 * & space. 117 * 118 * @see org.kuali.rice.krad.maintenance.Maintainable#prepareForSave 119 */ 120 @Override 121 public void prepareForSave() { 122 super.prepareForSave(); 123 124 TermSpecificationBo termSpec = (TermSpecificationBo) getDataObject(); 125 termSpec.getContexts().clear(); 126 } 127 128 /** 129 * For context addition, adds the item to the persisted contextValidTerms collection on the data object. 130 * 131 * <p>Without this step, the context is only added to a transient collection and the relationship will never be 132 * persisted. </p> 133 */ 134 @Override 135 public void processAfterAddLine(ViewModel viewModel, Object addLine, String collectionId, String collectionPath, 136 boolean isValidLine) { 137 // we only want to do our custom processing if a context has been added 138 if (addLine == null || !(addLine instanceof ContextBo)) { 139 super.processAfterAddLine(viewModel, addLine, collectionId, collectionPath, isValidLine); 140 return; 141 } 142 143 ContextBo addedContext = (ContextBo) addLine; 144 TermSpecificationBo termSpec = getDataObjectFromForm(viewModel); 145 146 boolean alreadyHasContextValidTerm = false; 147 148 for (ContextValidTermBo contextValidTerm : termSpec.getContextValidTerms()) { 149 if (contextValidTerm.getContextId().equals(addedContext.getId())) { 150 alreadyHasContextValidTerm = true; 151 break; 152 } 153 } 154 155 if (!alreadyHasContextValidTerm) { 156 ContextValidTermBo contextValidTerm = new ContextValidTermBo(); 157 contextValidTerm.setContextId(addedContext.getId()); 158 contextValidTerm.setTermSpecification(termSpec); 159 termSpec.getContextValidTerms().add(contextValidTerm); 160 } 161 } 162 163 /** 164 * For context removal, removes the given item from the persisted contextValidTerms collection on the data object. 165 * 166 * <p>Without this step, the context is only removed from a transient collection and the severed relationship will 167 * never be persisted. </p> 168 */ 169 @Override 170 public void processCollectionDeleteLine(ViewModel viewModel, String collectionId, String collectionPath, 171 int lineIndex) { 172 List collection = ObjectPropertyUtils.getPropertyValue(viewModel, collectionPath); 173 Object deletedItem = collection.get(lineIndex); 174 175 // we only want to do our custom processing if a context has been deleted 176 if (deletedItem == null || !(deletedItem instanceof ContextBo)) { 177 super.processCollectionDeleteLine(viewModel, collectionId, collectionPath, lineIndex); 178 return; 179 } 180 181 ContextBo context = (ContextBo) deletedItem; 182 TermSpecificationBo termSpec = getDataObjectFromForm(viewModel); 183 184 // find the context and remove it using the special powers of ListIterator 185 ListIterator<ContextValidTermBo> contextValidTermListIter = termSpec.getContextValidTerms().listIterator(); 186 while (contextValidTermListIter.hasNext()) { 187 ContextValidTermBo contextValidTerm = contextValidTermListIter.next(); 188 189 if (contextValidTerm.getContextId().equals(context.getId())) { 190 contextValidTerm.setTermSpecification(null); 191 contextValidTermListIter.remove(); 192 termSpec.getContexts().remove(context); 193 } 194 } 195 } 196 197 /** 198 * Pulls the data object out of the given form and returns it, casting it to the desired type. 199 * 200 * <p>Assumes that the form is actually a MaintenanceDocumentForm. The 201 * form.document.newMaintainableObject.dataObject is returned.</p> 202 * 203 * @param form 204 * @param <T> the type of data object to return 205 * @return the data object 206 */ 207 private static <T> T getDataObjectFromForm(ViewModel form) { 208 if (form == null) { return null; } 209 210 return (T) ((MaintenanceDocumentForm)form).getDocument().getNewMaintainableObject().getDataObject(); 211 } 212 213 @Override 214 public Class getDataObjectClass() { 215 return TermSpecificationBo.class; 216 } 217 218 /** 219 * Recreate the contexts from the contextIDs (needed due to serialization) 220 * 221 * @see org.kuali.rice.krad.maintenance.Maintainable#processAfterRetrieve 222 */ 223 @Override 224 public void processAfterRetrieve() { 225 super.processAfterRetrieve(); 226 } 227}