1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.ole.sys.batch.dataaccess.impl;
17
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.HashSet;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 import org.apache.commons.beanutils.PropertyUtils;
27 import org.apache.commons.lang.StringUtils;
28 import org.apache.log4j.Logger;
29 import org.apache.ojb.broker.query.QueryByCriteria;
30 import org.apache.ojb.broker.query.ReportQueryByCriteria;
31 import org.apache.ojb.broker.util.ObjectModification;
32 import org.kuali.ole.sys.batch.dataaccess.FiscalYearMaker;
33 import org.kuali.ole.sys.batch.dataaccess.FiscalYearMakersDao;
34 import org.kuali.ole.sys.businessobject.FiscalYearBasedBusinessObject;
35 import org.kuali.rice.core.framework.persistence.ojb.dao.PlatformAwareDaoBaseOjb;
36 import org.kuali.rice.krad.bo.PersistableBusinessObject;
37 import org.kuali.rice.krad.util.ObjectUtils;
38
39
40
41
42 public class FiscalYearMakersDaoOjb extends PlatformAwareDaoBaseOjb implements FiscalYearMakersDao {
43 private static final Logger LOG = org.apache.log4j.Logger.getLogger(FiscalYearMakersDaoOjb.class);
44
45 protected static final String KEY_STRING_DELIMITER = "|";
46
47
48
49
50
51 public void deleteNewYearRows(Integer baseYear, FiscalYearMaker objectFiscalYearMaker) {
52 if ( LOG.isInfoEnabled() ) {
53 LOG.info(String.format("\ndeleting %s for target year(s)", objectFiscalYearMaker.getBusinessObjectClass().getName()));
54 }
55
56 QueryByCriteria queryID = new QueryByCriteria(objectFiscalYearMaker.getBusinessObjectClass(), objectFiscalYearMaker.createDeleteCriteria(baseYear));
57 getPersistenceBrokerTemplate().deleteByQuery(queryID);
58
59 getPersistenceBrokerTemplate().clearCache();
60 }
61
62
63
64
65
66 public Collection<String> createNewYearRows(Integer baseYear, FiscalYearMaker fiscalYearMaker, boolean replaceMode, Map<Class<? extends FiscalYearBasedBusinessObject>, Set<String>> parentKeysWritten, boolean isParentClass) throws Exception {
67 if ( LOG.isInfoEnabled() ) {
68 LOG.info(String.format("\n copying %s from %d to %d", fiscalYearMaker.getBusinessObjectClass().getName(), baseYear, baseYear + 1));
69 }
70
71 int rowsRead = 0;
72 int rowsWritten = 0;
73 int rowsFailingRI = 0;
74
75
76 List<String> copyErrors = new ArrayList<String>();
77
78
79 Set<String> keysWritten = new HashSet<String>();
80
81
82 List<String> primaryKeyFields = fiscalYearMaker.getPrimaryKeyPropertyNames();
83
84 Set<String> nextYearPrimaryKeys = new HashSet<String>(2000);
85 LOG.info( "Loading Next Year's PKs for comparison");
86 ReportQueryByCriteria nextYearKeyQuery = new ReportQueryByCriteria(fiscalYearMaker.getBusinessObjectClass(), primaryKeyFields.toArray(new String[0]), fiscalYearMaker.createNextYearSelectionCriteria(baseYear) );
87 Iterator<Object[]> nextYearRecords = getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(nextYearKeyQuery);
88 StringBuilder keyString = new StringBuilder(40);
89 int numNextYearRecords = 0;
90 while ( nextYearRecords.hasNext() ) {
91 numNextYearRecords++;
92 keyString.setLength(0);
93 Object[] record = nextYearRecords.next();
94 for ( Object f : record ) {
95 keyString.append( f ).append( KEY_STRING_DELIMITER );
96 }
97 nextYearPrimaryKeys.add(keyString.toString());
98 if ( numNextYearRecords % 10000 == 0 ) {
99 if ( LOG.isInfoEnabled() ) {
100 LOG.info("Processing Record: " + numNextYearRecords);
101 }
102 }
103 }
104 if ( LOG.isInfoEnabled() ) {
105 LOG.info( "Completed load of next year keys. " + numNextYearRecords + " keys loaded.");
106 LOG.info( "Starting processing of existing FY rows" );
107 }
108
109 QueryByCriteria queryId = new QueryByCriteria(fiscalYearMaker.getBusinessObjectClass(), fiscalYearMaker.createSelectionCriteria(baseYear));
110
111 Iterator<FiscalYearBasedBusinessObject> recordsToCopy = getPersistenceBrokerTemplate().getIteratorByQuery(queryId);
112
113
114 while ( recordsToCopy.hasNext() ) {
115 FiscalYearBasedBusinessObject objectToCopy = recordsToCopy.next();
116 rowsRead++;
117 if ( LOG.isInfoEnabled() ) {
118 if ( rowsRead % 1000 == 0 ) {
119 LOG.info( "*** Processing Record: " + rowsRead + " -- Written So Far: " + rowsWritten + " -- Failing RI: " + rowsFailingRI + " -- Keys Written: " + keysWritten.size() );
120 }
121 }
122
123
124 removeNonPrimitiveFields(fiscalYearMaker, objectToCopy);
125
126
127 fiscalYearMaker.changeForNewYear(baseYear, objectToCopy);
128
129
130 if ( nextYearPrimaryKeys.contains(getKeyString(fiscalYearMaker, primaryKeyFields, objectToCopy)) ) {
131 if (isParentClass) {
132 addToKeysWritten(fiscalYearMaker, primaryKeyFields, objectToCopy, keysWritten);
133 }
134 continue;
135 }
136
137
138 if (!validateParentRecordsExist(fiscalYearMaker, objectToCopy, parentKeysWritten, copyErrors)) {
139 rowsFailingRI++;
140 continue;
141 }
142
143
144 getPersistenceBroker(true).store(objectToCopy, ObjectModification.INSERT);
145 rowsWritten++;
146 if (isParentClass) {
147 addToKeysWritten(fiscalYearMaker, primaryKeyFields, objectToCopy, keysWritten);
148 }
149 }
150
151 if (isParentClass) {
152 parentKeysWritten.put(fiscalYearMaker.getBusinessObjectClass(), keysWritten);
153 }
154
155 if ( LOG.isInfoEnabled() ) {
156 LOG.info(String.format("\n%s:\n%d read = %d\n%d written = %d\nfailed RI = %d", fiscalYearMaker.getBusinessObjectClass(), baseYear, rowsRead, baseYear + 1, rowsWritten, rowsFailingRI));
157 }
158
159 getPersistenceBrokerTemplate().clearCache();
160
161 return copyErrors;
162 }
163
164
165
166
167
168
169 protected void removeNonPrimitiveFields( FiscalYearMaker fiscalYearMaker, FiscalYearBasedBusinessObject businessObject) {
170 try {
171 @SuppressWarnings("rawtypes")
172 Map<String, Class> referenceFields = fiscalYearMaker.getReferenceObjectProperties();
173 for (String fieldName : referenceFields.keySet()) {
174 if (!fieldName.equals("extension")) {
175 PropertyUtils.setSimpleProperty(businessObject, fieldName, null);
176 }
177 }
178
179 @SuppressWarnings("rawtypes")
180 Map<String, Class> collectionFields = fiscalYearMaker.getCollectionProperties();
181 for (String fieldName : collectionFields.keySet()) {
182 PropertyUtils.setSimpleProperty(businessObject, fieldName, null);
183 }
184 } catch (Exception e) {
185 throw new RuntimeException("Unable to set non primitive fields to null: " + e.getMessage(), e);
186 }
187 }
188
189
190
191
192
193
194 protected boolean validateParentRecordsExist(FiscalYearMaker objectFiscalYearMaker, FiscalYearBasedBusinessObject childRecord, Map<Class<? extends FiscalYearBasedBusinessObject>, Set<String>> parentKeysWritten, List<String> copyErrors) throws Exception {
195
196 for (Class<? extends FiscalYearBasedBusinessObject> parentClass : objectFiscalYearMaker.getParentClasses()) {
197 if ( !validateChildParentReferencesExist(objectFiscalYearMaker,childRecord, parentClass, parentKeysWritten.get(parentClass), copyErrors) ) {
198 return false;
199 }
200 }
201
202 return true;
203 }
204
205
206
207
208
209
210
211
212
213
214
215 protected boolean validateChildParentReferencesExist(FiscalYearMaker objectFiscalYearMaker,FiscalYearBasedBusinessObject childRecord, Class<? extends FiscalYearBasedBusinessObject> parentClass, Set<String> parentKeys, List<String> copyErrors) throws Exception {
216 boolean allChildParentReferencesExist = true;
217 boolean foundParentReference = false;
218
219
220 @SuppressWarnings("rawtypes")
221 Map<String, Class> referenceObjects = objectFiscalYearMaker.getReferenceObjectProperties();
222
223
224 for (String referenceName : referenceObjects.keySet()) {
225 Class<? extends PersistableBusinessObject> referenceClass = referenceObjects.get(referenceName);
226
227 if (parentClass.isAssignableFrom(referenceClass)) {
228 foundParentReference = true;
229
230 String foreignKeyString = getForeignKeyStringForReference(objectFiscalYearMaker, childRecord, referenceName);
231 if (StringUtils.isNotBlank(foreignKeyString)
232 && !parentKeys.contains(foreignKeyString)) {
233
234 getPersistenceBroker(true).retrieveReference(childRecord, referenceName);
235 PersistableBusinessObject reference = (PersistableBusinessObject) PropertyUtils.getSimpleProperty(childRecord, referenceName);
236 if (ObjectUtils.isNull(reference)) {
237 allChildParentReferencesExist = false;
238 writeMissingParentCopyError(childRecord, parentClass, foreignKeyString, copyErrors);
239 LOG.warn( "Missing Parent Object: " + copyErrors.get(copyErrors.size()-1));
240 } else {
241 parentKeys.add(foreignKeyString);
242 }
243 }
244 }
245 }
246
247 if (!foundParentReference) {
248 LOG.warn(String.format("\n!!! NO relationships between child %s and parent %s found in OJB descriptor\n", childRecord.getClass().getName(), parentClass.getName()));
249 }
250
251 return allChildParentReferencesExist;
252 }
253
254
255
256
257
258
259
260
261 protected String getForeignKeyStringForReference( FiscalYearMaker fiscalYearMaker, FiscalYearBasedBusinessObject businessObject, String referenceName) throws Exception {
262 Map<String, String> foreignKeyToPrimaryKeyMap = fiscalYearMaker.getForeignKeyMappings( referenceName );
263
264 StringBuilder foreignKeyString = new StringBuilder(80);
265 for (String fkFieldName : foreignKeyToPrimaryKeyMap.keySet()) {
266 Object fkFieldValue = PropertyUtils.getSimpleProperty(businessObject, fkFieldName);
267 if (fkFieldValue != null) {
268 foreignKeyString.append( fkFieldValue.toString() ).append( KEY_STRING_DELIMITER );
269 } else {
270 foreignKeyString.setLength(0);
271 break;
272 }
273 }
274
275 return foreignKeyString.toString();
276 }
277
278
279
280
281
282
283
284
285
286 protected void writeMissingParentCopyError(FiscalYearBasedBusinessObject childRecord, Class<? extends FiscalYearBasedBusinessObject> parentClass, String foreignKeyString, Collection<String> copyErrors) {
287 StringBuilder errorCopyFailedMessage = new StringBuilder(150);
288 errorCopyFailedMessage.append(childRecord.getClass().getName());
289 errorCopyFailedMessage.append(" row for " + childRecord.toString());
290 errorCopyFailedMessage.append(" - " + foreignKeyString);
291 errorCopyFailedMessage.append(" not in ");
292 errorCopyFailedMessage.append(parentClass.getName());
293
294 copyErrors.add(errorCopyFailedMessage.toString());
295 }
296
297
298
299
300
301
302
303 protected void addToKeysWritten( FiscalYearMaker fiscalYearMaker, List<String> keyFieldNames, FiscalYearBasedBusinessObject copiedObject, Set<String> keysWritten) throws Exception {
304 keysWritten.add(getKeyString(fiscalYearMaker, keyFieldNames, copiedObject));
305 }
306
307 protected String getKeyString( FiscalYearMaker fiscalYearMaker, List<String> keyFieldNames, FiscalYearBasedBusinessObject businessObject ) throws Exception {
308 StringBuilder keyString = new StringBuilder(40);
309 for (String keyFieldName : keyFieldNames) {
310 keyString.append( PropertyUtils.getSimpleProperty(businessObject, keyFieldName) ).append( KEY_STRING_DELIMITER );
311 }
312 return keyString.toString();
313 }
314 }