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 }