import grails.util.GrailsUtil /** * Provides a data service to create a large volume of test data for load testing. */ class CreateBulkDataService { boolean transactional = false def authService def taskService def dateUtilService def appConfigService def searchableService def assignedGroupService def assignedPersonService def inventoryItemService def sessionFactory def grailsApplication def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP def startTime def lastBatchStarted /******************************************* Start of Group methods. Generally use these methods to create data. *******************************************/ /** * Make a run of data creation. */ def createAll() { def result = [:] def fail = { Map m -> result.error = [ code: m.code, args: m.args ] return result } if(GrailsUtil.environment != "development") return fail(code: 'default.not.development.environment.failure') log.info "Stop mirroring lucene index." searchableService.stopMirroring() log.info "Creating BULK data..." // Person and Utils log.info "Creating persons..." createBulkTestPersons() // createBulkTestSites() // createBulkTestDepartments() // createBulkTestSuppliers() // createBulkTestManufacturers() // Assets // createBulkTestLifePlan() // createBulkTestTaskProcedure() // createBulkTestMaintenanceActions() // createBulkTestSections() // createBulkTestAssets() // createBulkTestAssetExtenedAttributes() // createBulkTestAssetSubItems() // createBulkTestAssetSubItemExtenedAttributes() // Inventory log.info "Creating inventory..." // createBulkTestInventoryStores() /// @todo: Perhaps a 'createQuickStartData' method? createBulkTestInventoryLocations() // createBulkTestInventoryGroups() /// @todo: Perhaps a 'createQuickStartData' method? createBulkTestInventoryItems() // Tasks log.info "Creating tasks..." createBulkTestTasks() // createBulkTestEntries() // createBulkTestAssignedGroups() // createBulkTestAssignedPersons() // createBulkTestTaskRecurringSchedules() log.info "Creating BULK data...complete." log.info "Start mirroring Lucene index." searchableService.startMirroring() log.info "Rebuilding Lucene index, bulkIndex." searchableService.reindex() log.info "Rebuilding Lucene index, complete." return result } // create() /** * Make a run of inventory data creation. */ def createBulkInventoryTestData() { def result = [:] def fail = { Map m -> result.error = [ code: m.code, args: m.args ] return result } if(GrailsUtil.environment != "development") return fail(code: 'default.not.development.environment.failure') log.info "Stop mirroring Lucene index." searchableService.stopMirroring() log.info "Creating BULK data..." // Inventory log.info "Creating inventory..." // createBulkTestInventoryStores() /// @todo: Perhaps a 'createQuickStartData' method? createBulkTestInventoryLocations() // createBulkTestInventoryGroups() /// @todo: Perhaps a 'createQuickStartData' method? createBulkTestInventoryItems() log.info "Creating BULK data...complete." log.info "Start mirroring Lucene index." searchableService.startMirroring() log.info "Rebuilding Lucene index, bulkIndex." searchableService.reindex() log.info "Rebuilding Lucene index, complete." return result } // createBulkInventoryTestData() /****************** Start of Person *******************/ def createBulkTestPersons() { //Person def passClearText = "pass" def passwordEncoded = authService.encodePassword(passClearText) def personInstance def start = Person.count() + 1 def end = start + 100 def range = start..end def loginName = "BtLoginName" String btLoginName def firstName = "BtFirstName" String btFirstName def lastName = "BtLastName" def authority2 = Authority.get(2) def authority3 = Authority.get(3) def personGroup1 = PersonGroup.get(1) def personGroup2 = PersonGroup.get(2) def personGroup3 = PersonGroup.get(3) def personGroup4 = PersonGroup.get(4) def personGroup5 = PersonGroup.get(5) range.each() { btLoginName = loginName + it btFirstName = firstName + it personInstance = new Person(loginName: btLoginName, firstName: btFirstName, lastName: lastName, pass: passClearText, password: passwordEncoded) saveAndTest(personInstance) personInstance.addToAuthorities(authority2) personInstance.addToAuthorities(authority3) personInstance.addToPersonGroups(personGroup1) personInstance.addToPersonGroups(personGroup2) personInstance.addToPersonGroups(personGroup3) personInstance.addToPersonGroups(personGroup4) personInstance.addToPersonGroups(personGroup5) } } // createBulkTestPersons() /********************* START OF TASK *********************/ def createBulkTestTasks() { def taskResult def p = [:] def start = Task.count() + 1 def end = start + 10000 def range = start..end def taskGroup1 = TaskGroup.get(1) def taskPriority2 = TaskPriority.get(2) def taskType3 = TaskType.get(3) def leadPerson2 = Person.get(2) def description = "Bulk test data " String btDescription def comment1 = "Has been noted as problematic, try recalibrating." def today = dateUtilService.today startTime = System.currentTimeMillis() lastBatchStarted = startTime range.each() { if(it % 100 == 0) { logStatus("Creating task #" + it) cleanUpGorm() } btDescription = description + it //Task #1 p = [taskGroup: taskGroup1, taskPriority: taskPriority2, taskType: taskType3, leadPerson: leadPerson2, description: btDescription, comment: comment1, targetStartDate: today] taskResult = taskService.save(p) } } // createBulkTestTasks() def createBulkTestEntries() { def entryResult def p = [:] def range = 1..10 def task1 = Task.get(1) def entryType1 = EntryType.get(1) def comment1 = "This is a bulk test entry." def durationMinute1 = 20 range.each() { p = [task: task1, entryType: entryType1, comment: comment1, durationMinute: durationMinute1] entryResult = taskService.saveEntry(p) } } // createBulkTestEntries() /************************** START OF INVENTORY **************************/ def createBulkTestInventoryLocations() { def inventoryLocationResult def p = [:] def start = InventoryLocation.count() + 1 def end = start + 50 def range = start..end def inventoryStore1 = InventoryStore.read(1) def name = "Bulk test location " def btName = '' startTime = System.currentTimeMillis() lastBatchStarted = startTime range.each() { if(it % 25 == 0) { logStatus("Creating inventory location #" + it) cleanUpGorm() } btName = name + it p = [inventoryStore: inventoryStore1, name: btName] inventoryLocationResult = new InventoryLocation(p).save() } // each() } // createBulkTestInventoryLocations() def createBulkTestInventoryItems() { def inventoryItemInstance def p = [:] def pictureResource = grailsApplication.mainContext.getResource('images/logo.png') def start = InventoryItem.count() + 1 def end = start + 250 def range = start..end def inventoryLocation def inventoryLocationIndex = 0 def inventoryLocationList = InventoryLocation.findAll() def unitOfMeasure2 = UnitOfMeasure.read(2) def inventoryType1 = InventoryType.read(1) def inventoryGroup1 = InventoryGroup.read(1) def name = "Bulk test inventory item " def btName = '' startTime = System.currentTimeMillis() lastBatchStarted = startTime range.each() { if(it % 50 == 0) { logStatus("Creating inventory item #" + it) cleanUpGorm() } // Spread the inventoryItems across all available locations. if(inventoryLocationIndex < inventoryLocationList.size()) { inventoryLocation = inventoryLocationList[inventoryLocationIndex] } else { inventoryLocationIndex = 0 inventoryLocation = inventoryLocationList[inventoryLocationIndex] } inventoryLocationIndex++ // Change the name for each inventoryItem. btName = name + it p = [inventoryGroup: inventoryGroup1, inventoryType: inventoryType1, unitOfMeasure: unitOfMeasure2, inventoryLocation: inventoryLocation, name: btName, description: "Bulk test data", unitsInStock: 2, reorderPoint: 0] inventoryItemInstance = new InventoryItem(p) saveAndTest(inventoryItemInstance) def pictureResult = inventoryItemService.savePicture(inventoryItemInstance, pictureResource) if(pictureResult.error) log.error pictureResult.error } // each() } // createBulkTestInventoryItems() /** * This cleans up the hibernate session and a grails map. * For more info see: http://naleid.com/blog/2009/10/01/batch-import-performance-with-grails-and-mysql/ * The hibernate session flush is normal for hibernate. * The map is apparently used by grails for domain object validation errors. * A starting point for clean up is every 100 objects. */ def cleanUpGorm() { def session = sessionFactory.currentSession session.flush() session.clear() propertyInstanceMap.get().clear() } def logStatus(String message) { def batchEnded = System.currentTimeMillis() def seconds = (batchEnded-lastBatchStarted)/1000 def total = (batchEnded-startTime)/1000 log.info "${message}, last: ${seconds}s, total: ${total}s" lastBatchStarted = batchEnded } /**************************************** Call this function instead of .save() *****************************************/ private boolean saveAndTest(object) { if(!object.save()) { // BulkTestDataSuccessful = false log.error "'${object}' failed to save!" log.error object.errors return false } return true } } // end class.