+ (employee.salary as String)\n print \"${salary.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n println \"${employee.phone_number.center(BALANCE_COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n\n \/\/ second line in each output row\n print \"${COLUMN_SEPARATOR}${employee.hireDate.getDateString().center(COLUMN_WIDTH)}\"\n def managerName = employee.managerFirstName ? \"Mgr: ${employee.managerFirstName[0]}. ${employee.managerLastName}\" : \"Answers to No One\"\n print \"${COLUMN_SEPARATOR}${managerName.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n print \"${employee.departmentName.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n String commissionPercentage = employee.commissionPercentage ?: \"No Commission\"\n print \"${commissionPercentage.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n println \"${employee.emailAddress.center(BALANCE_COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n println ROW_SEPARATOR\n}\n\nThe last code snippet is where the data retrieved from the database is output in a relatively attractive text format. The example shows how handles in a closure can be named to be more meaningful. In this case, they are named id and employee and represent the key (Long) and value (Employee) of each entry in the TreeMap.\nThere are other Groovy features in the last code snippet worth special mention. The presentation of commission uses Groovy's Elvis operator (?:), which makes even Java's conditional ternary look verbose. In this example, if the employee's commission percentage meets Groovy truth standards, that percentage is used; otherwise, \"No Commission\" is printed.\nThe handling of the hire date provides another opportunity to tout Groovy's GDK benefits. In this case, Groovy GDK Date.getDateString() is used to easily access the date-only portion of the Date class (time not desired for hire date) without explicit use of a String formatter. Nice!\nThe last code example also demonstrates use of the as keyword to coerce (cast) variables in a more readable way and also demonstrates more leverage of Java features, in this case taking advantage of Java String's replace(CharSequence, CharSequence) method. Groovy adds some more goodness to String again in this example, however. The example demonstrates Groovy's supporting extracting the first letter only of the manager's first name using subscript (array) notation ([0]) to get only the first character out of the string.\nSo far in this post, I've shown snippets of the overall script as I explained the various features of Groovy that are demonstrated in each snippet. The entire script is shown next and that code listing is followed by a screen snapshot of how the output appears when the script is executed. The complete code for the Groovy Employee class was shown previously.\ngenerateReport.groovy: The Complete Script\n#!\/usr\/bin\/env groovy\n\n\/\/ Add JDBC driver to classpath as part of this script's bootstrapping.\n\/\/ See <a href=\"https:\/\/marxsoftware.blogspot.com\/2011\/02\/groovy-scripts-master-their-own.html\" rel=\"nofollow\">http:\/\/marxsoftware.blogspot.com\/2011\/02\/groovy-scripts-master-their-own...<\/a>.\n\/\/ WARNING: This location needs to be adjusted for specific user environment.\nthis.class.classLoader.rootLoader.addURL(\n new URL(\"file:\/\/\/C:\/oraclexe\/app\/oracle\/product\/11.2.0\/server\/jdbc\/lib\/ojdbc6.jar\"))\n\n\nint TOTAL_WIDTH = 120\nString HEADER_ROW_SEPARATOR = \"=\".multiply(TOTAL_WIDTH)\nString ROW_SEPARATOR = \"-\".multiply(TOTAL_WIDTH)\nString COLUMN_SEPARATOR = \"|\"\nint COLUMN_SEPARATOR_SIZE = COLUMN_SEPARATOR.size()\nint COLUMN_WIDTH = 22\nint TOTAL_NUM_COLUMNS = 5\nint BALANCE_COLUMN_WIDTH = TOTAL_WIDTH-(TOTAL_NUM_COLUMNS-1)*COLUMN_WIDTH-COLUMN_SEPARATOR_SIZE*(TOTAL_NUM_COLUMNS-1)-2\n\n\n\n\/\/ Get instance of Groovy's Sql class\n\/\/ See <a href=\"https:\/\/marxsoftware.blogspot.com\/2009\/05\/groovysql-groovy-jdbc.html\" rel=\"nofollow\">https:\/\/marxsoftware.blogspot.com\/2009\/05\/groovysql-groovy-jdbc.html<\/a>\nimport groovy.sql.Sql\ndef sql = Sql.newInstance(\"jdbc:oracle:thin:@localhost:1521:xe\", \"hr\", \"hr\",\n \"oracle.jdbc.pool.OracleDataSource\")\n\ndef employeeQueryStr =\n\"\"\"SELECT e.employee_id, e.first_name, e.last_name,\n e.email, e.phone_number,\n e.hire_date, e.job_id, j.job_title,\n e.salary, e.commission_pct, e.manager_id,\n e.department_id, d.department_name,\n m.first_name AS mgr_first_name, m.last_name AS mgr_last_name\n FROM employees e, departments d, jobs j, employees m\n WHERE e.department_id = d.department_id\n AND e.job_id = j.job_id\n AND e.manager_id = m.employee_id(+)\"\"\"\n\ndef employees = new TreeMap<Long, Employee>()\nsql.eachRow(employeeQueryStr)\n{\n def employeeId = it.employee_id as Long\n def employee = new Employee(employeeId, it.first_name, it.last_name,\n it.email, it.phone_number,\n it.hire_date, it.job_id, it.job_title,\n it.salary, it.commission_pct, it.manager_id as Long,\n it.department_id as Long, it.department_name,\n it.mgr_first_name, it.mgr_last_name)\n employees.put(employeeId, employee)\n}\n\nprintln \"nn${HEADER_ROW_SEPARATOR}\"\nprintln \"${COLUMN_SEPARATOR}${'HR SCHEMA EMPLOYEES'.center(TOTAL_WIDTH-2*COLUMN_SEPARATOR_SIZE)}${COLUMN_SEPARATOR}\"\nprintln HEADER_ROW_SEPARATOR\nprint \"${COLUMN_SEPARATOR}${'EMPLOYEE ID\/HIRE DATE'.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\nprint \"${'EMPLOYEE NAME'.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\nprint \"${'TITLE\/DEPARTMENT'.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\nprint \"${'SALARY INFO'.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\nprintln \"${'CONTACT INFO'.center(BALANCE_COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\nprintln HEADER_ROW_SEPARATOR\n\nemployees.each\n{ id, employee ->\n \/\/ first line in each row\n def idStr = id as String\n print \"${COLUMN_SEPARATOR}${idStr.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n def employeeName = employee.firstName + \" \" + employee.lastName\n print \"${employeeName.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n def jobTitle = employee.jobTitle.replace(\"Vice President\", \"VP\").replace(\"Assistant\", \"Asst\").replace(\"Representative\", \"Rep\")\n print \"${jobTitle.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n def salary = ' + (employee.salary as String)\n print \"${salary.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n println \"${employee.phone_number.center(BALANCE_COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n\n \/\/ second line in each row\n print \"${COLUMN_SEPARATOR}${employee.hireDate.getDateString().center(COLUMN_WIDTH)}\"\n def managerName = employee.managerFirstName ? \"Mgr: ${employee.managerFirstName[0]}. ${employee.managerLastName}\" : \"Answers to No One\"\n print \"${COLUMN_SEPARATOR}${managerName.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n print \"${employee.departmentName.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n String commissionPercentage = employee.commissionPercentage ?: \"No Commission\"\n print \"${commissionPercentage.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n println \"${employee.emailAddress.center(BALANCE_COLUMN_WIDTH)}${COLUMN_SEPARATOR}\"\n println ROW_SEPARATOR\n}\n\n\nIn this blog post, I've attempted to show how Groovy provides numerous features and other syntax support that make it easier to write scripts for generating readable and relatively attractive output. For more general Groovy scripts that provide text output support, see Formatting simple tabular text data. Although these are nice general solutions, an objective of my post has been to show that it is easy and does not take much time to write customized scripts for generating custom text output with Groovy. Small Groovy-isms such as easily centering a String, easily converting a Date to a String, extracting any desired character from a string based on array position notation, and easily accessing database data make Groovy a powerful tool in generating text-based reports.\nOriginal posting available at https:\/\/marxsoftware.blogspot.com\/ (Inspired by Actual Events)","wordCount":2538,"datePublished":"2012-11-24T22:11:00-05:00","dateModified":"2012-11-24T22:11:00-05:00","keywords":"Java","mainEntityOfPage":"https:\/\/www.infoworld.com\/article\/2158486\/scripted-reports-with-groovy.html"}]