001 /* 002 * Copyright 2011 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.kfs.sys.batch.dataaccess.impl; 017 018 import java.util.ArrayList; 019 import java.util.HashSet; 020 import java.util.List; 021 import java.util.Set; 022 023 import org.apache.commons.beanutils.PropertyUtils; 024 import org.apache.log4j.Logger; 025 import org.apache.ojb.broker.query.Criteria; 026 import org.kuali.kfs.sys.KFSConstants; 027 import org.kuali.kfs.sys.KFSPropertyConstants; 028 import org.kuali.kfs.sys.batch.dataaccess.FiscalYearMaker; 029 import org.kuali.kfs.sys.businessobject.SystemOptions; 030 import org.kuali.rice.kns.bo.Inactivateable; 031 import org.kuali.rice.kns.bo.PersistableBusinessObject; 032 import org.kuali.rice.kns.dao.impl.PlatformAwareDaoBaseOjb; 033 import org.kuali.rice.kns.service.PersistenceStructureService; 034 import org.kuali.rice.kns.util.Guid; 035 036 /** 037 * Default implementation of fiscal year maker process for an entity. This implementation can be used for a table in the fiscal year 038 * maker process by defining a spring bean and setting the businessObjectClass property. 039 */ 040 public class FiscalYearMakerImpl extends PlatformAwareDaoBaseOjb implements FiscalYearMaker { 041 private static Logger LOG = org.apache.log4j.Logger.getLogger(FiscalYearMakerImpl.class); 042 043 private PersistenceStructureService persistenceStructureService; 044 045 private Class<? extends PersistableBusinessObject> businessObjectClass; 046 private Set<Class<? extends PersistableBusinessObject>> parentClasses; 047 048 private boolean fiscalYearOneBehind; 049 private boolean fiscalYearOneAhead; 050 private boolean twoYearCopy; 051 private boolean carryForwardInactive; 052 private boolean allowOverrideTargetYear; 053 054 /** 055 * Constructs a FiscalYearMakerImpl.java. 056 */ 057 public FiscalYearMakerImpl() { 058 fiscalYearOneBehind = false; 059 fiscalYearOneAhead = false; 060 twoYearCopy = false; 061 carryForwardInactive = false; 062 allowOverrideTargetYear = true; 063 parentClasses = new HashSet<Class<? extends PersistableBusinessObject>>(); 064 } 065 066 /** 067 * Sets fiscal year field up one, resets version number and assigns a new Guid for the object id 068 * 069 * @see org.kuali.kfs.coa.dataaccess.FiscalYearMaker#changeForNewYear(java.lang.Integer, 070 * org.kuali.rice.kns.bo.PersistableBusinessObject) 071 */ 072 public void changeForNewYear(Integer baseFiscalYear, PersistableBusinessObject currentRecord) { 073 LOG.debug("starting changeForNewYear() for bo class " + businessObjectClass.getName()); 074 075 try { 076 // increment fiscal year by 1 077 Integer fiscalYear = (Integer) PropertyUtils.getProperty(currentRecord, KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR); 078 Integer newFiscalYear = fiscalYear + 1; 079 080 // update extension, must be done before updating main record so we can retrieve the extension record by reference 081 updateExtensionRecord(newFiscalYear, currentRecord); 082 083 // update main record fields 084 PropertyUtils.setSimpleProperty(currentRecord, KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, newFiscalYear); 085 086 currentRecord.setVersionNumber(new Long(1)); 087 currentRecord.setObjectId(new Guid().toString()); 088 } 089 catch (Exception e) { 090 String msg = String.format("Failed to set properties for class %s due to %s", businessObjectClass.getName(), e.getMessage()); 091 LOG.error(msg); 092 throw new RuntimeException(msg, e); 093 } 094 } 095 096 /** 097 * Determines if an extension record is mapped up and exists for the current record. If so then updates the version number, 098 * object id, and clears the primary keys so they will be relinked when storing the main record 099 * 100 * @param newFiscalYear fiscal year to set 101 * @param currentRecord main record with possible extension reference 102 */ 103 protected void updateExtensionRecord(Integer newFiscalYear, PersistableBusinessObject currentRecord) { 104 // check if reference is mapped up 105 if (!persistenceStructureService.hasReference(businessObjectClass, KFSPropertyConstants.EXTENSION)) { 106 return; 107 } 108 109 // try to retrieve extension record 110 currentRecord.refreshReferenceObject(KFSPropertyConstants.EXTENSION); 111 PersistableBusinessObject extension = currentRecord.getExtension(); 112 113 // if found then update fields 114 if (extension != null) { 115 extension.setVersionNumber(new Long(1)); 116 extension.setObjectId(new Guid().toString()); 117 118 // clear pk fields so they will be relinked 119 persistenceStructureService.clearPrimaryKeyFields(extension); 120 } 121 } 122 123 /** 124 * Selects records for the given base year or base year minus one if this is a lagging copy. If this is a two year copy base 125 * year plus one records will be selected as well. In addition will only select active records if the business object class 126 * implements the Inactivateable interface and has the active property. 127 * 128 * @see org.kuali.rice.kns.bo.Inactivateable 129 * @see org.kuali.kfs.coa.dataaccess.FiscalYearMaker#createSelectionCriteria(java.lang.Integer) 130 */ 131 public Criteria createSelectionCriteria(Integer baseFiscalYear) { 132 LOG.debug("starting createSelectionCriteria() for bo class " + businessObjectClass.getName()); 133 134 Criteria criteria = new Criteria(); 135 addYearCriteria(criteria, baseFiscalYear, false); 136 137 // add active criteria if the business object class supports the inactivateable interface 138 List<String> fields = persistenceStructureService.listFieldNames(businessObjectClass); 139 if (Inactivateable.class.isAssignableFrom(businessObjectClass) && fields.contains(KFSPropertyConstants.ACTIVE) && !carryForwardInactive) { 140 criteria.addEqualTo(KFSPropertyConstants.ACTIVE, KFSConstants.ACTIVE_INDICATOR); 141 } 142 143 return criteria; 144 } 145 146 /** 147 * Selects records to delete for base year + 1 (or base year for lagging, and base year + 2 for two year) 148 * 149 * @see org.kuali.kfs.coa.batch.dataaccess.FiscalYearMakerHelper#createDeleteCriteria(java.lang.Integer) 150 */ 151 public Criteria createDeleteCriteria(Integer baseFiscalYear) { 152 LOG.debug("starting createDeleteCriteria() for bo class " + businessObjectClass.getName()); 153 154 Criteria criteria = new Criteria(); 155 addYearCriteria(criteria, baseFiscalYear + 1, twoYearCopy); 156 157 return criteria; 158 } 159 160 /** 161 * Adds fiscal year criteria based on the configuration (copy two years, lagging, or normal) 162 * 163 * @param criteria OJB Criteria object 164 * @param baseFiscalYear Fiscal year for critiera 165 * @param createTwoYears indicates whether two years of fiscal year criteria should be added 166 */ 167 protected void addYearCriteria(Criteria criteria, Integer baseFiscalYear, boolean createTwoYears) { 168 verifyUniversityFiscalYearPropertyExists(); 169 170 if (fiscalYearOneBehind) { 171 baseFiscalYear = baseFiscalYear - 1; 172 } 173 else if (fiscalYearOneAhead) { 174 baseFiscalYear = baseFiscalYear + 1; 175 } 176 177 if (createTwoYears) { 178 List<Integer> copyYears = new ArrayList<Integer>(); 179 copyYears.add(baseFiscalYear); 180 copyYears.add(baseFiscalYear + 1); 181 182 criteria.addIn(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, copyYears); 183 } 184 else { 185 criteria.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, baseFiscalYear); 186 } 187 } 188 189 /** 190 * Verifies the given business object class has the university fiscal year property necessary for setting default criteria 191 * 192 * @see org.kuali.kfs.sys.KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR 193 */ 194 protected void verifyUniversityFiscalYearPropertyExists() { 195 List<String> fields = persistenceStructureService.listFieldNames(businessObjectClass); 196 if (fields == null || !fields.contains(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR)) { 197 String msg = String.format("No %s property in business object class %s", KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, businessObjectClass.getName()); 198 LOG.error(msg); 199 throw new RuntimeException(msg); 200 } 201 } 202 203 /** 204 * Default implementation does nothing 205 * 206 * @see org.kuali.kfs.coa.batch.dataaccess.FiscalYearMakerHelper#performCustomProcessing(java.lang.Integer) 207 */ 208 public void performCustomProcessing(Integer baseFiscalYear, boolean firstCopyYear) { 209 210 } 211 212 /** 213 * Default to doing both normal FYM process and custom 214 * 215 * @see org.kuali.kfs.coa.batch.dataaccess.FiscalYearMakerHelper#doCustomProcessingOnly() 216 */ 217 public boolean doCustomProcessingOnly() { 218 return false; 219 } 220 221 /** 222 * @see org.kuali.kfs.coa.dataaccess.FiscalYearMaker#getBusinessObjectClass() 223 */ 224 public Class<? extends PersistableBusinessObject> getBusinessObjectClass() { 225 return businessObjectClass; 226 } 227 228 /** 229 * <code>Options</code> is the parent for univFiscalYear which all our copy objects should have. Added to list here by default. 230 * 231 * @see org.kuali.kfs.coa.batch.dataaccess.FiscalYearMakerHelper#getParentClasses() 232 * @see org.kuali.kfs.sys.businessobject.Options 233 */ 234 public Set<Class<? extends PersistableBusinessObject>> getParentClasses() { 235 if (!businessObjectClass.equals(SystemOptions.class) && !parentClasses.contains(SystemOptions.class)) { 236 parentClasses.add(SystemOptions.class); 237 } 238 239 return parentClasses; 240 } 241 242 /** 243 * Sets the businessObjectClass attribute value. 244 * 245 * @param businessObjectClass The businessObjectClass to set. 246 */ 247 public void setBusinessObjectClass(Class<? extends PersistableBusinessObject> businessObjectClass) { 248 this.businessObjectClass = businessObjectClass; 249 } 250 251 /** 252 * Sets the parentClasses attribute value. 253 * 254 * @param parentClasses The parentClasses to set. 255 */ 256 public void setParentClasses(Set<Class<? extends PersistableBusinessObject>> parentClasses) { 257 this.parentClasses = parentClasses; 258 } 259 260 /** 261 * Gets the fiscalYearOneBehind attribute. 262 * 263 * @return Returns the fiscalYearOneBehind. 264 */ 265 public boolean isFiscalYearOneBehind() { 266 return fiscalYearOneBehind; 267 } 268 269 /** 270 * Sets the fiscalYearOneBehind attribute value. 271 * 272 * @param fiscalYearOneBehind The fiscalYearOneBehind to set. 273 */ 274 public void setFiscalYearOneBehind(boolean fiscalYearOneBehind) { 275 this.fiscalYearOneBehind = fiscalYearOneBehind; 276 } 277 278 /** 279 * Gets the fiscalYearOneAhead attribute. 280 * 281 * @return Returns the fiscalYearOneAhead. 282 */ 283 public boolean isFiscalYearOneAhead() { 284 return fiscalYearOneAhead; 285 } 286 287 /** 288 * Sets the fiscalYearOneAhead attribute value. 289 * 290 * @param fiscalYearOneAhead The fiscalYearOneAhead to set. 291 */ 292 public void setFiscalYearOneAhead(boolean fiscalYearOneAhead) { 293 this.fiscalYearOneAhead = fiscalYearOneAhead; 294 } 295 296 /** 297 * Gets the twoYearCopy attribute. 298 * 299 * @return Returns the twoYearCopy. 300 */ 301 public boolean isTwoYearCopy() { 302 return twoYearCopy; 303 } 304 305 /** 306 * Sets the twoYearCopy attribute value. 307 * 308 * @param twoYearCopy The twoYearCopy to set. 309 */ 310 public void setTwoYearCopy(boolean twoYearCopy) { 311 this.twoYearCopy = twoYearCopy; 312 } 313 314 /** 315 * Gets the carryForwardInactive attribute. 316 * 317 * @return Returns the carryForwardInactive. 318 */ 319 public boolean isCarryForwardInactive() { 320 return carryForwardInactive; 321 } 322 323 /** 324 * Sets the carryForwardInactive attribute value. 325 * 326 * @param carryForwardInactive The carryForwardInactive to set. 327 */ 328 public void setCarryForwardInactive(boolean carryForwardInactive) { 329 this.carryForwardInactive = carryForwardInactive; 330 } 331 332 /** 333 * Sets the persistenceStructureService attribute value. 334 * 335 * @param persistenceStructureService The persistenceStructureService to set. 336 */ 337 public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) { 338 this.persistenceStructureService = persistenceStructureService; 339 } 340 341 /** 342 * Gets the allowOverrideTargetYear attribute. 343 * 344 * @return Returns the allowOverrideTargetYear. 345 */ 346 public boolean isAllowOverrideTargetYear() { 347 return allowOverrideTargetYear; 348 } 349 350 /** 351 * Sets the allowOverrideTargetYear attribute value. 352 * 353 * @param allowOverrideTargetYear The allowOverrideTargetYear to set. 354 */ 355 public void setAllowOverrideTargetYear(boolean allowOverrideTargetYear) { 356 this.allowOverrideTargetYear = allowOverrideTargetYear; 357 } 358 359 }