| [258] | 1 | import grails.util.GrailsUtil | 
|---|
|  | 2 |  | 
|---|
|  | 3 | /** | 
|---|
|  | 4 | * Provides a data service to create a large volume of test data for load testing. | 
|---|
|  | 5 | */ | 
|---|
|  | 6 | class  CreateBulkDataService { | 
|---|
|  | 7 |  | 
|---|
|  | 8 | boolean transactional = false | 
|---|
|  | 9 |  | 
|---|
| [291] | 10 | def authService | 
|---|
| [258] | 11 | def taskService | 
|---|
|  | 12 | def dateUtilService | 
|---|
|  | 13 | def appConfigService | 
|---|
| [572] | 14 | def searchableService | 
|---|
| [258] | 15 | def assignedGroupService | 
|---|
|  | 16 | def assignedPersonService | 
|---|
| [548] | 17 | def inventoryItemService | 
|---|
| [258] | 18 |  | 
|---|
|  | 19 | def sessionFactory | 
|---|
| [548] | 20 | def grailsApplication | 
|---|
| [258] | 21 | def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP | 
|---|
|  | 22 |  | 
|---|
| [261] | 23 | def startTime | 
|---|
|  | 24 | def lastBatchStarted | 
|---|
| [258] | 25 |  | 
|---|
|  | 26 | /******************************************* | 
|---|
|  | 27 | Start of Group methods. | 
|---|
|  | 28 | Generally use these methods to create data. | 
|---|
|  | 29 | *******************************************/ | 
|---|
|  | 30 |  | 
|---|
|  | 31 | /** | 
|---|
|  | 32 | * Make a run of data creation. | 
|---|
|  | 33 | */ | 
|---|
| [548] | 34 | def createAll() { | 
|---|
|  | 35 | def result = [:] | 
|---|
|  | 36 |  | 
|---|
|  | 37 | def fail = { Map m -> | 
|---|
|  | 38 | result.error = [ code: m.code, args: m.args ] | 
|---|
|  | 39 | return result | 
|---|
| [258] | 40 | } | 
|---|
|  | 41 |  | 
|---|
| [548] | 42 | if(GrailsUtil.environment != "development") | 
|---|
|  | 43 | return fail(code: 'default.not.development.environment.failure') | 
|---|
|  | 44 |  | 
|---|
| [572] | 45 | log.info "Stop mirroring lucene index." | 
|---|
|  | 46 | searchableService.stopMirroring() | 
|---|
|  | 47 |  | 
|---|
| [258] | 48 | log.info "Creating BULK data..." | 
|---|
|  | 49 |  | 
|---|
|  | 50 | // Person and Utils | 
|---|
|  | 51 | log.info "Creating persons..." | 
|---|
|  | 52 | createBulkTestPersons() | 
|---|
|  | 53 | //         createBulkTestSites() | 
|---|
|  | 54 | //         createBulkTestDepartments() | 
|---|
|  | 55 | //         createBulkTestSuppliers() | 
|---|
|  | 56 | //         createBulkTestManufacturers() | 
|---|
|  | 57 |  | 
|---|
| [548] | 58 | // Assets | 
|---|
|  | 59 | //         createBulkTestLifePlan() | 
|---|
|  | 60 | //         createBulkTestTaskProcedure() | 
|---|
|  | 61 | //         createBulkTestMaintenanceActions() | 
|---|
|  | 62 | //         createBulkTestSections() | 
|---|
|  | 63 | //         createBulkTestAssets() | 
|---|
|  | 64 | //         createBulkTestAssetExtenedAttributes() | 
|---|
|  | 65 | //         createBulkTestAssetSubItems() | 
|---|
|  | 66 | //         createBulkTestAssetSubItemExtenedAttributes() | 
|---|
|  | 67 |  | 
|---|
|  | 68 | // Inventory | 
|---|
|  | 69 | log.info "Creating inventory..." | 
|---|
|  | 70 | //         createBulkTestInventoryStores()  /// @todo: Perhaps a 'createQuickStartData' method? | 
|---|
|  | 71 | createBulkTestInventoryLocations() | 
|---|
|  | 72 | //         createBulkTestInventoryGroups() /// @todo: Perhaps a 'createQuickStartData' method? | 
|---|
|  | 73 | createBulkTestInventoryItems() | 
|---|
|  | 74 |  | 
|---|
| [258] | 75 | // Tasks | 
|---|
|  | 76 | log.info "Creating tasks..." | 
|---|
|  | 77 | createBulkTestTasks() | 
|---|
|  | 78 | //         createBulkTestEntries() | 
|---|
|  | 79 | //         createBulkTestAssignedGroups() | 
|---|
|  | 80 | //         createBulkTestAssignedPersons() | 
|---|
|  | 81 | //         createBulkTestTaskRecurringSchedules() | 
|---|
|  | 82 |  | 
|---|
| [548] | 83 | log.info "Creating BULK data...complete." | 
|---|
| [572] | 84 |  | 
|---|
| [580] | 85 | log.info "Start mirroring Lucene index." | 
|---|
| [572] | 86 | searchableService.startMirroring() | 
|---|
| [580] | 87 | log.info "Rebuilding Lucene index, bulkIndex." | 
|---|
| [572] | 88 | searchableService.reindex() | 
|---|
| [580] | 89 | log.info "Rebuilding Lucene index, complete." | 
|---|
| [572] | 90 |  | 
|---|
| [548] | 91 | return result | 
|---|
|  | 92 |  | 
|---|
|  | 93 | } // create() | 
|---|
|  | 94 |  | 
|---|
|  | 95 | /** | 
|---|
|  | 96 | * Make a run of inventory data creation. | 
|---|
|  | 97 | */ | 
|---|
|  | 98 | def createBulkInventoryTestData() { | 
|---|
|  | 99 | def result = [:] | 
|---|
|  | 100 |  | 
|---|
|  | 101 | def fail = { Map m -> | 
|---|
|  | 102 | result.error = [ code: m.code, args: m.args ] | 
|---|
|  | 103 | return result | 
|---|
|  | 104 | } | 
|---|
|  | 105 |  | 
|---|
|  | 106 | if(GrailsUtil.environment != "development") | 
|---|
|  | 107 | return fail(code: 'default.not.development.environment.failure') | 
|---|
|  | 108 |  | 
|---|
| [580] | 109 | log.info "Stop mirroring Lucene index." | 
|---|
| [572] | 110 | searchableService.stopMirroring() | 
|---|
|  | 111 |  | 
|---|
| [548] | 112 | log.info "Creating BULK data..." | 
|---|
|  | 113 |  | 
|---|
| [258] | 114 | // Inventory | 
|---|
| [548] | 115 | log.info "Creating inventory..." | 
|---|
| [258] | 116 | //         createBulkTestInventoryStores()  /// @todo: Perhaps a 'createQuickStartData' method? | 
|---|
| [548] | 117 | createBulkTestInventoryLocations() | 
|---|
| [258] | 118 | //         createBulkTestInventoryGroups() /// @todo: Perhaps a 'createQuickStartData' method? | 
|---|
| [548] | 119 | createBulkTestInventoryItems() | 
|---|
| [258] | 120 |  | 
|---|
|  | 121 | log.info "Creating BULK data...complete." | 
|---|
| [572] | 122 |  | 
|---|
| [580] | 123 | log.info "Start mirroring Lucene index." | 
|---|
| [572] | 124 | searchableService.startMirroring() | 
|---|
| [580] | 125 | log.info "Rebuilding Lucene index, bulkIndex." | 
|---|
| [572] | 126 | searchableService.reindex() | 
|---|
| [580] | 127 | log.info "Rebuilding Lucene index, complete." | 
|---|
| [572] | 128 |  | 
|---|
| [548] | 129 | return result | 
|---|
| [258] | 130 |  | 
|---|
| [548] | 131 | } // createBulkInventoryTestData() | 
|---|
| [258] | 132 |  | 
|---|
|  | 133 | /****************** | 
|---|
|  | 134 | Start of Person | 
|---|
|  | 135 | *******************/ | 
|---|
|  | 136 |  | 
|---|
|  | 137 | def createBulkTestPersons() { | 
|---|
|  | 138 | //Person | 
|---|
|  | 139 | def passClearText = "pass" | 
|---|
| [291] | 140 | def passwordEncoded = authService.encodePassword(passClearText) | 
|---|
| [258] | 141 | def personInstance | 
|---|
|  | 142 |  | 
|---|
| [261] | 143 | def start = Person.count() + 1 | 
|---|
|  | 144 | def end = start + 100 | 
|---|
| [258] | 145 |  | 
|---|
| [261] | 146 | def range = start..end | 
|---|
|  | 147 |  | 
|---|
| [258] | 148 | def loginName = "BtLoginName" | 
|---|
|  | 149 | String btLoginName | 
|---|
|  | 150 | def firstName = "BtFirstName" | 
|---|
|  | 151 | String btFirstName | 
|---|
|  | 152 | def lastName = "BtLastName" | 
|---|
|  | 153 |  | 
|---|
|  | 154 | def authority2 = Authority.get(2) | 
|---|
|  | 155 | def authority3 = Authority.get(3) | 
|---|
|  | 156 | def personGroup1 = PersonGroup.get(1) | 
|---|
|  | 157 | def personGroup2 = PersonGroup.get(2) | 
|---|
|  | 158 | def personGroup3 = PersonGroup.get(3) | 
|---|
|  | 159 | def personGroup4 = PersonGroup.get(4) | 
|---|
|  | 160 | def personGroup5 = PersonGroup.get(5) | 
|---|
|  | 161 |  | 
|---|
|  | 162 | range.each() { | 
|---|
|  | 163 |  | 
|---|
|  | 164 | btLoginName = loginName + it | 
|---|
|  | 165 | btFirstName = firstName + it | 
|---|
|  | 166 |  | 
|---|
|  | 167 | personInstance = new Person(loginName: btLoginName, | 
|---|
|  | 168 | firstName: btFirstName, | 
|---|
|  | 169 | lastName: lastName, | 
|---|
|  | 170 | pass: passClearText, | 
|---|
| [399] | 171 | password: passwordEncoded) | 
|---|
| [258] | 172 | saveAndTest(personInstance) | 
|---|
|  | 173 | personInstance.addToAuthorities(authority2) | 
|---|
|  | 174 | personInstance.addToAuthorities(authority3) | 
|---|
|  | 175 | personInstance.addToPersonGroups(personGroup1) | 
|---|
|  | 176 | personInstance.addToPersonGroups(personGroup2) | 
|---|
|  | 177 | personInstance.addToPersonGroups(personGroup3) | 
|---|
|  | 178 | personInstance.addToPersonGroups(personGroup4) | 
|---|
|  | 179 | personInstance.addToPersonGroups(personGroup5) | 
|---|
|  | 180 |  | 
|---|
|  | 181 | } | 
|---|
|  | 182 |  | 
|---|
|  | 183 | } // createBulkTestPersons() | 
|---|
|  | 184 |  | 
|---|
|  | 185 | /********************* | 
|---|
|  | 186 | START OF TASK | 
|---|
|  | 187 | *********************/ | 
|---|
|  | 188 |  | 
|---|
|  | 189 | def createBulkTestTasks() { | 
|---|
|  | 190 |  | 
|---|
|  | 191 | def taskResult | 
|---|
|  | 192 | def p = [:] | 
|---|
|  | 193 |  | 
|---|
| [261] | 194 | def start = Task.count() + 1 | 
|---|
|  | 195 | def end = start + 10000 | 
|---|
| [258] | 196 |  | 
|---|
| [261] | 197 | def range = start..end | 
|---|
| [258] | 198 |  | 
|---|
| [261] | 199 |  | 
|---|
| [258] | 200 | def taskGroup1 = TaskGroup.get(1) | 
|---|
|  | 201 | def taskPriority2 = TaskPriority.get(2) | 
|---|
| [418] | 202 | def taskType3 = TaskType.get(3) | 
|---|
| [258] | 203 | def leadPerson2 = Person.get(2) | 
|---|
|  | 204 |  | 
|---|
|  | 205 | def description = "Bulk test data " | 
|---|
|  | 206 | String btDescription | 
|---|
|  | 207 | def comment1 = "Has been noted as problematic, try recalibrating." | 
|---|
|  | 208 | def today = dateUtilService.today | 
|---|
|  | 209 |  | 
|---|
| [261] | 210 | startTime = System.currentTimeMillis() | 
|---|
|  | 211 | lastBatchStarted = startTime | 
|---|
|  | 212 |  | 
|---|
| [258] | 213 | range.each() { | 
|---|
|  | 214 |  | 
|---|
| [261] | 215 | if(it % 100 == 0) { | 
|---|
| [258] | 216 | logStatus("Creating task #" + it) | 
|---|
|  | 217 | cleanUpGorm() | 
|---|
|  | 218 | } | 
|---|
|  | 219 |  | 
|---|
|  | 220 | btDescription = description + it | 
|---|
|  | 221 |  | 
|---|
|  | 222 | //Task #1 | 
|---|
|  | 223 | p = [taskGroup: taskGroup1, | 
|---|
|  | 224 | taskPriority: taskPriority2, | 
|---|
| [418] | 225 | taskType: taskType3, | 
|---|
| [258] | 226 | leadPerson: leadPerson2, | 
|---|
|  | 227 | description: btDescription, | 
|---|
|  | 228 | comment: comment1, | 
|---|
|  | 229 | targetStartDate: today] | 
|---|
|  | 230 |  | 
|---|
| [394] | 231 | taskResult = taskService.save(p) | 
|---|
| [258] | 232 | } | 
|---|
|  | 233 |  | 
|---|
| [548] | 234 | } // createBulkTestTasks() | 
|---|
| [258] | 235 |  | 
|---|
|  | 236 | def createBulkTestEntries() { | 
|---|
|  | 237 |  | 
|---|
|  | 238 | def entryResult | 
|---|
|  | 239 | def p = [:] | 
|---|
|  | 240 |  | 
|---|
|  | 241 | def range = 1..10 | 
|---|
|  | 242 | def task1 = Task.get(1) | 
|---|
|  | 243 | def entryType1 = EntryType.get(1) | 
|---|
|  | 244 | def comment1 = "This is a bulk test entry." | 
|---|
|  | 245 | def durationMinute1 = 20 | 
|---|
|  | 246 |  | 
|---|
|  | 247 | range.each() { | 
|---|
|  | 248 |  | 
|---|
|  | 249 | p = [task: task1, | 
|---|
|  | 250 | entryType: entryType1, | 
|---|
|  | 251 | comment: comment1, | 
|---|
|  | 252 | durationMinute: durationMinute1] | 
|---|
|  | 253 |  | 
|---|
| [394] | 254 | entryResult = taskService.saveEntry(p) | 
|---|
| [258] | 255 |  | 
|---|
|  | 256 | } | 
|---|
|  | 257 |  | 
|---|
|  | 258 | } // createBulkTestEntries() | 
|---|
|  | 259 |  | 
|---|
| [548] | 260 |  | 
|---|
|  | 261 | /************************** | 
|---|
|  | 262 | START OF INVENTORY | 
|---|
|  | 263 | **************************/ | 
|---|
|  | 264 |  | 
|---|
|  | 265 | def createBulkTestInventoryLocations() { | 
|---|
|  | 266 |  | 
|---|
|  | 267 | def inventoryLocationResult | 
|---|
|  | 268 | def p = [:] | 
|---|
|  | 269 |  | 
|---|
|  | 270 | def start = InventoryLocation.count() + 1 | 
|---|
|  | 271 | def end = start + 50 | 
|---|
|  | 272 |  | 
|---|
|  | 273 | def range = start..end | 
|---|
|  | 274 |  | 
|---|
|  | 275 |  | 
|---|
|  | 276 | def inventoryStore1 = InventoryStore.read(1) | 
|---|
|  | 277 |  | 
|---|
|  | 278 | def name = "Bulk test location " | 
|---|
|  | 279 | def btName = '' | 
|---|
|  | 280 |  | 
|---|
|  | 281 | startTime = System.currentTimeMillis() | 
|---|
|  | 282 | lastBatchStarted = startTime | 
|---|
|  | 283 |  | 
|---|
|  | 284 | range.each() { | 
|---|
|  | 285 |  | 
|---|
| [572] | 286 | if(it % 25 == 0) { | 
|---|
| [548] | 287 | logStatus("Creating inventory location #" + it) | 
|---|
|  | 288 | cleanUpGorm() | 
|---|
|  | 289 | } | 
|---|
|  | 290 |  | 
|---|
|  | 291 | btName = name + it | 
|---|
|  | 292 |  | 
|---|
|  | 293 | p = [inventoryStore: inventoryStore1, | 
|---|
|  | 294 | name: btName] | 
|---|
|  | 295 |  | 
|---|
|  | 296 | inventoryLocationResult = new InventoryLocation(p).save() | 
|---|
|  | 297 | } // each() | 
|---|
|  | 298 |  | 
|---|
|  | 299 | } // createBulkTestInventoryLocations() | 
|---|
|  | 300 |  | 
|---|
|  | 301 | def createBulkTestInventoryItems() { | 
|---|
|  | 302 |  | 
|---|
|  | 303 | def inventoryItemInstance | 
|---|
|  | 304 | def p = [:] | 
|---|
|  | 305 |  | 
|---|
|  | 306 | def pictureResource = grailsApplication.mainContext.getResource('images/logo.png') | 
|---|
|  | 307 |  | 
|---|
|  | 308 | def start = InventoryItem.count() + 1 | 
|---|
|  | 309 | def end = start + 250 | 
|---|
|  | 310 |  | 
|---|
|  | 311 | def range = start..end | 
|---|
|  | 312 |  | 
|---|
|  | 313 | def inventoryLocation | 
|---|
|  | 314 | def inventoryLocationIndex = 0 | 
|---|
|  | 315 | def inventoryLocationList = InventoryLocation.findAll() | 
|---|
|  | 316 | def unitOfMeasure2 = UnitOfMeasure.read(2) | 
|---|
|  | 317 | def inventoryType1 = InventoryType.read(1) | 
|---|
|  | 318 | def inventoryGroup1 = InventoryGroup.read(1) | 
|---|
|  | 319 |  | 
|---|
|  | 320 | def name = "Bulk test inventory item " | 
|---|
|  | 321 | def btName = '' | 
|---|
|  | 322 |  | 
|---|
|  | 323 | startTime = System.currentTimeMillis() | 
|---|
|  | 324 | lastBatchStarted = startTime | 
|---|
|  | 325 |  | 
|---|
|  | 326 | range.each() { | 
|---|
|  | 327 |  | 
|---|
| [572] | 328 | if(it % 50 == 0) { | 
|---|
| [548] | 329 | logStatus("Creating inventory item #" + it) | 
|---|
|  | 330 | cleanUpGorm() | 
|---|
|  | 331 | } | 
|---|
|  | 332 |  | 
|---|
|  | 333 | // Spread the inventoryItems across all available locations. | 
|---|
|  | 334 | if(inventoryLocationIndex < inventoryLocationList.size()) { | 
|---|
|  | 335 | inventoryLocation = inventoryLocationList[inventoryLocationIndex] | 
|---|
|  | 336 | } | 
|---|
|  | 337 | else { | 
|---|
|  | 338 | inventoryLocationIndex = 0 | 
|---|
|  | 339 | inventoryLocation = inventoryLocationList[inventoryLocationIndex] | 
|---|
|  | 340 | } | 
|---|
|  | 341 | inventoryLocationIndex++ | 
|---|
|  | 342 |  | 
|---|
|  | 343 | // Change the name for each inventoryItem. | 
|---|
|  | 344 | btName = name + it | 
|---|
|  | 345 |  | 
|---|
|  | 346 | p = [inventoryGroup: inventoryGroup1, | 
|---|
|  | 347 | inventoryType: inventoryType1, | 
|---|
|  | 348 | unitOfMeasure: unitOfMeasure2, | 
|---|
|  | 349 | inventoryLocation: inventoryLocation, | 
|---|
|  | 350 | name: btName, | 
|---|
|  | 351 | description: "Bulk test data", | 
|---|
|  | 352 | unitsInStock: 2, | 
|---|
|  | 353 | reorderPoint: 0] | 
|---|
|  | 354 |  | 
|---|
|  | 355 | inventoryItemInstance = new InventoryItem(p) | 
|---|
|  | 356 | saveAndTest(inventoryItemInstance) | 
|---|
|  | 357 |  | 
|---|
|  | 358 | def pictureResult = inventoryItemService.savePicture(inventoryItemInstance, pictureResource) | 
|---|
|  | 359 |  | 
|---|
|  | 360 | if(pictureResult.error) | 
|---|
|  | 361 | log.error pictureResult.error | 
|---|
|  | 362 | } // each() | 
|---|
|  | 363 |  | 
|---|
|  | 364 | } // createBulkTestInventoryItems() | 
|---|
|  | 365 |  | 
|---|
| [258] | 366 | /** | 
|---|
|  | 367 | * This cleans up the hibernate session and a grails map. | 
|---|
|  | 368 | * For more info see: http://naleid.com/blog/2009/10/01/batch-import-performance-with-grails-and-mysql/ | 
|---|
|  | 369 | * The hibernate session flush is normal for hibernate. | 
|---|
|  | 370 | * The map is apparently used by grails for domain object validation errors. | 
|---|
|  | 371 | * A starting point for clean up is every 100 objects. | 
|---|
|  | 372 | */ | 
|---|
|  | 373 | def cleanUpGorm() { | 
|---|
|  | 374 | def session = sessionFactory.currentSession | 
|---|
|  | 375 | session.flush() | 
|---|
|  | 376 | session.clear() | 
|---|
|  | 377 | propertyInstanceMap.get().clear() | 
|---|
|  | 378 | } | 
|---|
|  | 379 |  | 
|---|
|  | 380 | def logStatus(String message) { | 
|---|
|  | 381 | def batchEnded = System.currentTimeMillis() | 
|---|
|  | 382 | def seconds = (batchEnded-lastBatchStarted)/1000 | 
|---|
|  | 383 | def total = (batchEnded-startTime)/1000 | 
|---|
|  | 384 | log.info "${message}, last: ${seconds}s, total: ${total}s" | 
|---|
|  | 385 | lastBatchStarted = batchEnded | 
|---|
|  | 386 | } | 
|---|
|  | 387 |  | 
|---|
|  | 388 |  | 
|---|
|  | 389 | /**************************************** | 
|---|
|  | 390 | Call this function instead of .save() | 
|---|
|  | 391 | *****************************************/ | 
|---|
|  | 392 | private boolean saveAndTest(object) { | 
|---|
|  | 393 | if(!object.save()) { | 
|---|
|  | 394 | //             BulkTestDataSuccessful = false | 
|---|
|  | 395 | log.error "'${object}' failed to save!" | 
|---|
|  | 396 | log.error object.errors | 
|---|
|  | 397 | return false | 
|---|
|  | 398 | } | 
|---|
|  | 399 | return true | 
|---|
|  | 400 | } | 
|---|
|  | 401 |  | 
|---|
|  | 402 | } // end class. | 
|---|