From a158b55c1dca427bcef0f5cfb03ee7f760841317 Mon Sep 17 00:00:00 2001 From: sudhir nimavat Date: Wed, 17 Apr 2019 20:47:16 +0530 Subject: [PATCH 1/2] Upgrade to grails 339 and use shipkit, add circleci --- .circleci/config.yml | 85 ++ build.gradle | 145 +-- examples/app/build.gradle | 17 +- .../app/grails-app/conf/application.groovy | 2 +- examples/app/grails-app/conf/logback.groovy | 2 +- .../app/grails-app/domain/foo/Bills.groovy | 3 + .../app/grails-app/domain/foo/Customer.groovy | 4 + .../app/grails-app/domain/foo/Product.groovy | 3 + .../grails-app/domain/foo/ProductGroup.groovy | 3 + .../app/grails-app/init/Application.groovy | 2 +- .../nine/reports/DomainMetaUtilsSpec.groovy | 2 + .../dynamic/DynamicReportsServiceSpec.groovy | 60 +- examples/sandbox-dynamic-jasper/build.gradle | 15 +- .../conf/DefaultDynamicJasperConfig.groovy | 212 ++--- .../grails-app/conf/application.groovy | 2 +- .../grails-app/conf/logback.groovy | 2 +- .../controllers/foo/NotNullPutAt.groovy | 28 +- .../foo/ToStringCustomExpression.groovy | 54 +- .../grails-app/domain/foo/Bills.groovy | 3 - .../grails-app/init/Application.groovy | 2 +- gradle.properties | 40 +- gradle/codenarck-rules.groovy | 386 -------- gradle/common-publishing.gradle | 45 - gradle/shipkit.gradle | 8 + gradlew | 6 +- grailsw | 151 ---- grailsw.bat | 89 -- plugin/build.gradle | 40 +- .../conf/JasperReportsDefaultConfig.groovy | 1 - .../init/nine/jasper/Application.groovy | 2 +- .../services/nine/jasper/JasperService.groovy | 76 +- .../nine/jasper/JasperViewService.groovy | 20 +- .../dynamic/DynamicReportsService.groovy | 86 +- .../nine/jasper/JRDataSourceJDBC.groovy | 7 +- .../jasper/JasperReportsGrailsPlugin.groovy | 133 +-- .../groovy/nine/jasper/JasperUtils.groovy | 167 ++-- .../nine/jasper/dynamic/StyleStatics.groovy | 551 ++++++------ .../nine/jasper/dynamic/TemplateStyles.groovy | 381 ++++---- .../jasper/gorm/GormJasperDataSource.groovy | 86 +- .../spring/AbstractJasperReportsView.groovy | 830 +++++++++--------- .../nine/jasper/spring/JasperReportDef.groovy | 90 +- .../nine/jasper/spring/JasperView.groovy | 472 +++++----- .../jasper/spring/JasperViewResolver.groovy | 31 +- .../nine/reports/DomainMetaUtils.groovy | 66 +- .../groovy/nine/reports/FieldMetadata.groovy | 8 +- .../groovy/nine/reports/ReportFormat.groovy | 13 +- .../jrsamples/datasource/CustomBean.groovy | 59 +- .../datasource/CustomBeanFactory.groovy | 102 +-- .../jrsamples/datasource/NestPropsSpec.groovy | 2 +- .../jrsamples/datasource/RunCustomSpec.groovy | 2 +- settings.gradle | 2 +- version.properties | 8 + 52 files changed, 1997 insertions(+), 2609 deletions(-) create mode 100644 .circleci/config.yml delete mode 100644 gradle/codenarck-rules.groovy delete mode 100644 gradle/common-publishing.gradle create mode 100644 gradle/shipkit.gradle delete mode 100755 grailsw delete mode 100755 grailsw.bat create mode 100644 version.properties diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..dd52c9a --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,85 @@ + +version: 2 +jobs: + build: + docker: + # docker image with python and mkdocs on it already as well, based on gradle:4.6-alpine + - image: dock9/gradle:4.6 + + # Specify service dependencies here if necessary + # CircleCI maintains a library of pre-built images + # documented at https://circleci.com/docs/2.0/circleci-images/ + # - image: circleci/postgres:9.4 + +# branches: +# only: +# - master + + # working_directory: ~/repo + + environment: + # Customize the JVM maximum heap limit + # JVM_OPTS: -Xmx3200m + MALLOC_ARENA_MAX: 2 + GRADLE_OPTS: "-Xmx3200m -Dorg.gradle.daemon=false" #daemon false doesn't seem to get picked up by fork + TERM: dumb + + parallelism: 1 + # resource_class: large + + steps: + - checkout + + # Download and cache dependencies + - restore_cache: + keys: + - v3-gradle-{{ checksum "build.gradle" }} + + # see https://github.com/palantir/gradle-configuration-resolver-plugin + - run: ./gradlew resolveConfigurations + #- run: ./gradlew test-app:dependencies + + - save_cache: + paths: + - /home/gradle # the https://hub.docker.com/_/gradle/ containter does wierd stuff for cache + - ~/.m2 + - ~/.gradle + key: v3-gradle-{{ checksum "build.gradle" }} + +# - add_ssh_keys: +# fingerprints: +# - "32:15:5c:47:98:e9:3f:09:f9:32:c9:22:00:cc:15:9a" + + #- run: gradle build -s && gradle ciPublish + - run: + name: gradle check tests. skips if only docs were changed + command: | + commitRange=$(echo "$CIRCLE_COMPARE_URL" | rev | cut -d/ -f1 | rev) + if [[ -z "$commitRange" || $(git diff --name-only $commitRange | grep --invert-match -E "(README\.md|mkdocs\.yml|docs/)") ]]; then + ./gradlew check + fi + + - run: ./gradlew ciPublish + + - store_artifacts: + path: plugin/build/reports/tests/test/ + destination: test-reports/unit/ + + - store_artifacts: + path: plugin/build/reports/codenarc/ + destination: codenarc/ + + - store_test_results: + path: plugin/build/test-results + + # - run: gradle test-app:check --no-daemon --max-workers 2 + + - store_artifacts: + path: examples/test-app/build/reports/tests + destination: test-reports/integration + + - store_test_results: + path: examples/test-app/build/test-results + + + # - run: ./.circleci/publish.sh diff --git a/build.gradle b/build.gradle index 8f24ec5..f482617 100644 --- a/build.gradle +++ b/build.gradle @@ -1,124 +1,59 @@ buildscript { - repositories { - mavenLocal() - maven { url "https://repo.grails.org/grails/core" } - } - dependencies { - classpath "org.grails:grails-gradle-plugin:$grailsVersion" - classpath "org.grails:grails-docs:$grailsVersion" - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' - classpath 'io.github.groovylang.groovydoc:groovydoc-gradle-plugin:1.0.1' - classpath "com.bertramlabs.plugins:asset-pipeline-gradle:2.8.2" - } + repositories { + mavenLocal() + maven { url "https://repo.grails.org/grails/core" } + } + dependencies { + classpath "org.grails:grails-gradle-plugin:$grailsVersion" + classpath "org.yakworks:gradle-plugins:0.1.45" + } } -apply plugin: 'idea' -apply plugin:'groovy' +apply plugin: 'yakworks.shipkit' repositories { - mavenLocal() - maven { url "https://repo.grails.org/grails/core" } + mavenLocal() + maven { url "https://repo.grails.org/grails/core" } + maven { url "http://repo.9ci.com/oss-snapshots" } } -//Root project and view-tools plugin uses same version. -version project.projectVersion - -project(':jasper-reports') { - version = project.projectVersion -} - -ext { - commonBuild = new File(project.rootDir, "gradle").absolutePath - grailsApps = ['test-app', 'dynamic-jasper'] - grailsPlugins = ['jasper-reports'] -} - - subprojects { + apply plugin: 'groovy' + plugins.withId('java') { - boolean isGrailsApp = grailsApps.contains(project.name) - boolean isGrailsPlugin = grailsPlugins.contains(project.name) - boolean isGrailsProject = isGrailsApp || isGrailsPlugin - boolean isBuildSnapshot = version.toString().endsWith("-SNAPSHOT") - - println project.name + ":" + version.toString() - - ext { - userOrg = "grails" - set "tomcat.version", "8.5.5" - isSnapshot = isBuildSnapshot - } - - apply plugin:'groovy' - - sourceCompatibility = '1.8' - targetCompatibility = '1.8' - - repositories { - mavenLocal() - maven { url "https://repo.grails.org/grails/core" } - } - - dependencies { - compile "org.springframework.boot:spring-boot-starter-logging" - compile "org.springframework.boot:spring-boot-autoconfigure" - compile "org.grails:grails-core" - compile "org.grails:grails-dependencies" - compile "org.grails:grails-web-boot" - compile "org.grails.plugins:cache" - - runtime "com.h2database:h2" - - testCompile "org.grails:grails-plugin-testing" - - testCompile "org.grails:grails-gorm-testing-support:1.1.4" - testCompile "org.grails:grails-web-testing-support:1.1.4" - } - - - if (isGrailsPlugin) { - println "Grails plugin ###" - group "org.grails.plugins" - - apply plugin:"org.grails.grails-plugin" - apply plugin:"org.grails.grails-gsp" - - apply from: "${commonBuild}/common-publishing.gradle" - - dependencies { - compile "org.springframework.boot:spring-boot-starter-actuator" - provided "org.springframework.boot:spring-boot-starter-tomcat" - - profile "org.grails.profiles:web-plugin" - provided "org.grails:grails-plugin-services" - provided "org.grails:grails-plugin-domain-class" - - console "org.grails:grails-console" - } + sourceCompatibility = '1.8' + targetCompatibility = '1.8' - } + repositories { + mavenLocal() + maven { url "https://repo.grails.org/grails/core" } + maven { url "http://repo.9ci.com/oss-snapshots" } + } - if (isGrailsApp) { - group "org.grails" + dependencies { + compile "org.springframework.boot:spring-boot-starter-logging" + compile "org.springframework.boot:spring-boot-autoconfigure" + compile "org.grails:grails-core" + compile "org.grails:grails-dependencies" + compile "org.grails:grails-web-boot" + compile "org.grails.plugins:cache" + runtime "com.h2database:h2" - apply plugin:"org.grails.grails-web" - apply plugin:"war" - apply plugin:"org.grails.grails-gsp" + compile "org.grails.plugins:hibernate5" + compile "org.hibernate:hibernate-core:$versionHibernate" + compile "org.hibernate:hibernate-ehcache:$versionHibernate" - dependencies { - profile "org.grails.profiles:web" - compile "org.springframework.boot:spring-boot-starter-actuator" - provided "org.springframework.boot:spring-boot-starter-tomcat" + testCompile "org.grails:grails-plugin-testing" - console "org.grails:grails-console" - } + testCompile "org.grails:grails-gorm-testing-support" + testCompile "org.grails:grails-web-testing-support" + } - bootRun { - jvmArgs('-Dspring.output.ansi.enabled=always') - addResources = true - } + test { + testLogging.exceptionFormat = 'full' + } - } + } } diff --git a/examples/app/build.gradle b/examples/app/build.gradle index 0149c81..e694395 100644 --- a/examples/app/build.gradle +++ b/examples/app/build.gradle @@ -1,10 +1,19 @@ version "0.1" +apply plugin: "org.grails.grails-web" +apply plugin: "war" +apply plugin: "org.grails.grails-gsp" + dependencies { - compile "org.grails.plugins:hibernate5" - compile "org.hibernate:hibernate-core:5.1.1.Final" - compile "org.hibernate:hibernate-ehcache:5.1.1.Final" + profile "org.grails.profiles:web" + + provided "org.grails:grails-plugin-domain-class" + provided "org.grails:grails-plugin-services" + + compile "org.springframework.boot:spring-boot-starter-actuator" + provided "org.springframework.boot:spring-boot-starter-tomcat" + provided "org.codehaus.groovy:groovy-ant" } @@ -19,4 +28,4 @@ grails { println "Inside grails: $rootProject.name" compile project(':jasper-reports') } -} \ No newline at end of file +} diff --git a/examples/app/grails-app/conf/application.groovy b/examples/app/grails-app/conf/application.groovy index f1a595d..6e43d21 100644 --- a/examples/app/grails-app/conf/application.groovy +++ b/examples/app/grails-app/conf/application.groovy @@ -6,4 +6,4 @@ jasper { } } -} \ No newline at end of file +} diff --git a/examples/app/grails-app/conf/logback.groovy b/examples/app/grails-app/conf/logback.groovy index dbc8f74..1288e8b 100644 --- a/examples/app/grails-app/conf/logback.groovy +++ b/examples/app/grails-app/conf/logback.groovy @@ -49,4 +49,4 @@ if (Environment.developmentMode && targetDir) { logger "grails.app.services.foobar", DEBUG,['STDOUT'] logger "org.grails.gsp.GroovyPageResourceLoader", DEBUG,['STDOUT'] logger "org.grails.gsp.io.DefaultGroovyPageLocator", DEBUG,['STDOUT'] -} \ No newline at end of file +} diff --git a/examples/app/grails-app/domain/foo/Bills.groovy b/examples/app/grails-app/domain/foo/Bills.groovy index 645738f..2334c09 100644 --- a/examples/app/grails-app/domain/foo/Bills.groovy +++ b/examples/app/grails-app/domain/foo/Bills.groovy @@ -1,5 +1,8 @@ package foo +import grails.compiler.GrailsCompileStatic + +@GrailsCompileStatic class Bills { Customer customer diff --git a/examples/app/grails-app/domain/foo/Customer.groovy b/examples/app/grails-app/domain/foo/Customer.groovy index cdd3cde..14fbe19 100644 --- a/examples/app/grails-app/domain/foo/Customer.groovy +++ b/examples/app/grails-app/domain/foo/Customer.groovy @@ -1,11 +1,15 @@ package foo +import grails.compiler.GrailsCompileStatic + /** * Created by basejump on 10/15/16. */ +@GrailsCompileStatic class Customer { String num String name + static constraints = { num nullable:true } diff --git a/examples/app/grails-app/domain/foo/Product.groovy b/examples/app/grails-app/domain/foo/Product.groovy index a73d260..669ee75 100644 --- a/examples/app/grails-app/domain/foo/Product.groovy +++ b/examples/app/grails-app/domain/foo/Product.groovy @@ -1,8 +1,11 @@ package foo +import grails.compiler.GrailsCompileStatic + /** * Created by basejump on 10/15/16. */ +@GrailsCompileStatic class Product { ProductGroup group String num diff --git a/examples/app/grails-app/domain/foo/ProductGroup.groovy b/examples/app/grails-app/domain/foo/ProductGroup.groovy index e4387a0..33754d0 100644 --- a/examples/app/grails-app/domain/foo/ProductGroup.groovy +++ b/examples/app/grails-app/domain/foo/ProductGroup.groovy @@ -1,8 +1,11 @@ package foo +import grails.compiler.GrailsCompileStatic + /** * Created by basejump on 10/15/16. */ +@GrailsCompileStatic class ProductGroup { String name } diff --git a/examples/app/grails-app/init/Application.groovy b/examples/app/grails-app/init/Application.groovy index 372bf9d..83c1fad 100644 --- a/examples/app/grails-app/init/Application.groovy +++ b/examples/app/grails-app/init/Application.groovy @@ -7,4 +7,4 @@ class Application extends GrailsAutoConfiguration { static void main(String[] args) { GrailsApp.run(Application, args) } -} \ No newline at end of file +} diff --git a/examples/app/src/test/groovy/nine/reports/DomainMetaUtilsSpec.groovy b/examples/app/src/test/groovy/nine/reports/DomainMetaUtilsSpec.groovy index 6013a94..244f593 100644 --- a/examples/app/src/test/groovy/nine/reports/DomainMetaUtilsSpec.groovy +++ b/examples/app/src/test/groovy/nine/reports/DomainMetaUtilsSpec.groovy @@ -7,6 +7,7 @@ import foo.ProductGroup import grails.testing.gorm.DataTest import grails.testing.web.GrailsWebUnitTest import org.grails.datastore.mapping.model.PersistentEntity +import spock.lang.Ignore import spock.lang.Specification class DomainMetaUtilsSpec extends Specification implements DataTest, GrailsWebUnitTest { @@ -28,6 +29,7 @@ class DomainMetaUtilsSpec extends Specification implements DataTest, GrailsWebUn assert colmap['name'] } + @Ignore('https://github.com/yakworks/grails-jasper-reports/issues/11') void "buildColumnMap works with config on Bills and nested properties"() { given: PersistentEntity domainClass = grailsApplication.mappingContext.getPersistentEntity(Bills.name) diff --git a/examples/app/src/test/groovy/nine/reports/dynamic/DynamicReportsServiceSpec.groovy b/examples/app/src/test/groovy/nine/reports/dynamic/DynamicReportsServiceSpec.groovy index 9803a4e..93499e8 100644 --- a/examples/app/src/test/groovy/nine/reports/dynamic/DynamicReportsServiceSpec.groovy +++ b/examples/app/src/test/groovy/nine/reports/dynamic/DynamicReportsServiceSpec.groovy @@ -10,6 +10,7 @@ import net.sf.dynamicreports.jasper.builder.JasperReportBuilder import nine.jasper.dynamic.DynamicReportsService import nine.reports.DomainMetaUtils import nine.reports.SeedData +import spock.lang.Ignore import spock.lang.Shared import static net.sf.dynamicreports.report.builder.DynamicReports.export @@ -17,7 +18,7 @@ import static net.sf.dynamicreports.report.builder.DynamicReports.export //@Domain([ProductGroup,Bills,Customer,Product]) class DynamicReportsServiceSpec extends HibernateSpec implements DataTest { - List getDomainClasses() { [ProductGroup,Bills,Customer,Product] } + List getDomainClasses() { [ProductGroup, Customer, Bills, Product] } @Shared DynamicReportsService dynamicReportsService = new DynamicReportsService() @@ -33,58 +34,59 @@ class DynamicReportsServiceSpec extends HibernateSpec implements DataTest { */ static folder = new File("target/reports/DynamicReportsServiceSpec/"); - void setupSpec(){ - mockDomains(ProductGroup,Bills,Customer,Product) + void setupSpec() { + mockDomains(ProductGroup, Customer, Bills, Product) dynamicReportsService = new DynamicReportsService() dynamicReportsService.grailsApplication = grailsApplication - if(!folder.exists()) folder.mkdirs(); + if (!folder.exists()) folder.mkdirs(); } - List getData(orderBy){ - return Bills.createCriteria().list{ - def o = DomainMetaUtils.orderNested(orderBy,delegate) + List getData(orderBy) { + return Bills.createCriteria().list { + def o = DomainMetaUtils.orderNested(orderBy, delegate) o() } } - def saveToFiles(JasperReportBuilder dr, fname){ + def saveToFiles(JasperReportBuilder dr, fname) { //dr.toJrXml(new FileOutputStream( new File(folder,"${fname}.jrxml"))) long start = System.currentTimeMillis(); - dr.toPdf(new FileOutputStream( new File(folder,"${fname}.pdf"))) + dr.toPdf(new FileOutputStream(new File(folder, "${fname}.pdf"))) System.err.println("PDF time : " + (System.currentTimeMillis() - start)); start = System.currentTimeMillis(); dr.ignorePagination()//.ignorePageWidth() //.setPageFormat(PageType.LETTER, PageOrientation.LANDSCAPE) - .rebuild() + .rebuild() //.toHtml(new FileOutputStream( new File(folder,"basic.html"))) - def htmlRpt = new File(folder,"${fname}.html") + def htmlRpt = new File(folder, "${fname}.html") dr.toHtml( - export.htmlExporter(new FileOutputStream( htmlRpt)) - .setHtmlHeader(getHTMLHeader()) - .setHtmlFooter(HTMLFooter) //.setFramesAsNestedTables(true).setZoomRatio(200) + export.htmlExporter(new FileOutputStream(htmlRpt)) + .setHtmlHeader(getHTMLHeader()) + .setHtmlFooter(HTMLFooter) //.setFramesAsNestedTables(true).setZoomRatio(200) ) System.err.println("HTML time : " + (System.currentTimeMillis() - start)); - dr.toJrXml(new FileOutputStream( new File(folder,"${fname}.jrxml"))) + dr.toJrXml(new FileOutputStream(new File(folder, "${fname}.jrxml"))) "open target/reports/DynamicReportsServiceSpec/${fname}.html".execute() } + @Ignore("https://github.com/yakworks/grails-jasper-reports/issues/11") void "simple sanity check"() { when: - Map cfg = [ - domain:'Bills', - fields: ['customer.name','product.group.name', 'color','product.name','isPaid', 'tranDate', 'qty', 'amount'], - columns:['tranProp':'From Getter'], - groups: ['customer.name', 'product.group.name','color'], - subtotals: [qty:"sum", amount:"sum"], //put these on all the group summaries - subtotalsHeader: [amount:"sum"], //put these on all the group summaries - columnHeaderInFirstGroup:true, //for each new primary group value the column header will be reprinted, if false they occur once per page - groupTotalLabels:true, //puts a group total label on the subtotal footers - //highlightDetailOddRows:true, - showGridLines:true, + Map cfg = [ + domain : 'Bills', + fields : ['customer.name', 'product.group.name', 'color', 'product.name', 'isPaid', 'tranDate', 'qty', 'amount'], + columns : ['tranProp': 'From Getter'], + groups : ['customer.name', 'product.group.name', 'color'], + subtotals : [qty: "sum", amount: "sum"], //put these on all the group summaries + subtotalsHeader : [amount: "sum"], //put these on all the group summaries + columnHeaderInFirstGroup: true, //for each new primary group value the column header will be reprinted, if false they occur once per page + groupTotalLabels : true, //puts a group total label on the subtotal footers + //highlightDetailOddRows:true, + showGridLines : true, // tableOfContents:true, // landscape:true //short cut for pageFormat:[size:'letter', landscape:true] // pageFormat:[size:'letter', landscape:true] // [size:'letter',landscape:false] is the default. Size can be letter,legal, A0-C10, basically any static in net.sf.dynamicreports.report.constant.PageType @@ -98,7 +100,7 @@ class DynamicReportsServiceSpec extends HibernateSpec implements DataTest { assert dr //dr.setPageFormat(PageType.LETTER, PageOrientation.LANDSCAPE) - saveToFiles(dr,'basic') + saveToFiles(dr, 'basic') //dr.show() //sleep(5000) @@ -146,7 +148,7 @@ class DynamicReportsServiceSpec extends HibernateSpec implements DataTest { // //sleep(5000) // } -String HTMLHeader = (''' + String HTMLHeader = (''' @@ -161,7 +163,7 @@ String HTMLHeader = ('''   ''').toString() -String HTMLFooter = ''' + String HTMLFooter = '''   diff --git a/examples/sandbox-dynamic-jasper/build.gradle b/examples/sandbox-dynamic-jasper/build.gradle index 12f156f..8c2b857 100644 --- a/examples/sandbox-dynamic-jasper/build.gradle +++ b/examples/sandbox-dynamic-jasper/build.gradle @@ -1,10 +1,16 @@ version "0.1" +apply plugin: "org.grails.grails-web" +apply plugin: "war" +apply plugin: "org.grails.grails-gsp" + dependencies { - compile "org.grails.plugins:hibernate5" - compile "org.hibernate:hibernate-core:5.1.1.Final" - compile "org.hibernate:hibernate-ehcache:5.1.1.Final" + profile "org.grails.profiles:web" + + compile "org.springframework.boot:spring-boot-starter-actuator" + provided "org.springframework.boot:spring-boot-starter-tomcat" + provided "org.codehaus.groovy:groovy-ant" compile('ar.com.fdvs:DynamicJasper:5.0.10'){ @@ -12,7 +18,6 @@ dependencies { } //build('ar.com.fdvs:DynamicJasper-core-fonts:1.0') - } bootRun { @@ -26,4 +31,4 @@ grails { println "Inside grails: $rootProject.name" compile project(':jasper-reports') } -} \ No newline at end of file +} diff --git a/examples/sandbox-dynamic-jasper/grails-app/conf/DefaultDynamicJasperConfig.groovy b/examples/sandbox-dynamic-jasper/grails-app/conf/DefaultDynamicJasperConfig.groovy index 45c80b1..387e5c6 100644 --- a/examples/sandbox-dynamic-jasper/grails-app/conf/DefaultDynamicJasperConfig.groovy +++ b/examples/sandbox-dynamic-jasper/grails-app/conf/DefaultDynamicJasperConfig.groovy @@ -1,106 +1,106 @@ -import ar.com.fdvs.dj.domain.constants.Font -import ar.com.fdvs.dj.domain.constants.Border -import java.awt.Color -import ar.com.fdvs.dj.domain.constants.Transparency -import ar.com.fdvs.dj.domain.constants.HorizontalAlign -import ar.com.fdvs.dj.domain.constants.VerticalAlign -import ar.com.fdvs.dj.domain.constants.Rotation -import ar.com.fdvs.dj.domain.constants.Stretching -import ar.com.fdvs.dj.domain.constants.Page - -dynamicJasper { - - useFullPageWidth = true - - page = Page.Page_Legal_Portrait() - - isUsingImagesToAlign = true - - intPattern = '#0' - floatPattern = '#0.00' - datePattern = 'MM/dd/yyyy' - - titleStyle { - font = new Font(18, Font._FONT_VERDANA,true) - textColor = Color.black - border = Border.NO_BORDER() - borderColor = Color.darkGray - horizontalAlign = HorizontalAlign.CENTER - verticalAlign = VerticalAlign.MIDDLE - backgroundColor = Color.white - transparency = Transparency.OPAQUE - transparent = false - blankWhenNull = true - padding = 2 - pattern = '' - radius = 1 - rotation = Rotation.NONE - stretching = Stretching.NO_STRETCH - stretchWithOverflow = false - } - - groupStyle { - - } - - subtitleStyle { - font = new Font(14, Font._FONT_VERDANA, false) - textColor = Color.black - border = Border.NO_BORDER() - borderColor = Color.darkGray - horizontalAlign = HorizontalAlign.LEFT - verticalAlign = VerticalAlign.MIDDLE - backgroundColor = Color.white - transparency = Transparency.OPAQUE - transparent = false - blankWhenNull = true - padding = 2 - pattern = '' - radius = 1 - rotation = Rotation.NONE - stretching = Stretching.NO_STRETCH - stretchWithOverflow = false - } - - headerStyle { - font = Font.ARIAL_MEDIUM_BOLD - textColor = Color.black - border = Border.THIN() - borderColor = Color.darkGray - horizontalAlign = HorizontalAlign.CENTER - verticalAlign = VerticalAlign.MIDDLE - backgroundColor = Color.decode("#f9fafb") - transparency = Transparency.OPAQUE - transparent = false - blankWhenNull = true - padding = 2 - pattern = '' - radius = 1 - rotation = Rotation.NONE - stretching = Stretching.NO_STRETCH - stretchWithOverflow = false - } - - detailStyle { - font = Font.ARIAL_MEDIUM - textColor = Color.black - borderTop = Border.NO_BORDER() - borderBottom = Border.THIN() - borderLeft = Border.NO_BORDER() - borderRight = Border.NO_BORDER() - borderColor = Color.LIGHT_GRAY - horizontalAlign = HorizontalAlign.LEFT - verticalAlign = VerticalAlign.MIDDLE - backgroundColor = Color.white - transparency = Transparency.OPAQUE - //transparent = false - blankWhenNull = true - padding = 4 - //pattern = '' - radius = 1 - rotation = Rotation.NONE - stretching = Stretching.NO_STRETCH - stretchWithOverflow = false - } - -} \ No newline at end of file +import ar.com.fdvs.dj.domain.constants.Font +import ar.com.fdvs.dj.domain.constants.Border +import java.awt.Color +import ar.com.fdvs.dj.domain.constants.Transparency +import ar.com.fdvs.dj.domain.constants.HorizontalAlign +import ar.com.fdvs.dj.domain.constants.VerticalAlign +import ar.com.fdvs.dj.domain.constants.Rotation +import ar.com.fdvs.dj.domain.constants.Stretching +import ar.com.fdvs.dj.domain.constants.Page + +dynamicJasper { + + useFullPageWidth = true + + page = Page.Page_Legal_Portrait() + + isUsingImagesToAlign = true + + intPattern = '#0' + floatPattern = '#0.00' + datePattern = 'MM/dd/yyyy' + + titleStyle { + font = new Font(18, Font._FONT_VERDANA,true) + textColor = Color.black + border = Border.NO_BORDER() + borderColor = Color.darkGray + horizontalAlign = HorizontalAlign.CENTER + verticalAlign = VerticalAlign.MIDDLE + backgroundColor = Color.white + transparency = Transparency.OPAQUE + transparent = false + blankWhenNull = true + padding = 2 + pattern = '' + radius = 1 + rotation = Rotation.NONE + stretching = Stretching.NO_STRETCH + stretchWithOverflow = false + } + + groupStyle { + + } + + subtitleStyle { + font = new Font(14, Font._FONT_VERDANA, false) + textColor = Color.black + border = Border.NO_BORDER() + borderColor = Color.darkGray + horizontalAlign = HorizontalAlign.LEFT + verticalAlign = VerticalAlign.MIDDLE + backgroundColor = Color.white + transparency = Transparency.OPAQUE + transparent = false + blankWhenNull = true + padding = 2 + pattern = '' + radius = 1 + rotation = Rotation.NONE + stretching = Stretching.NO_STRETCH + stretchWithOverflow = false + } + + headerStyle { + font = Font.ARIAL_MEDIUM_BOLD + textColor = Color.black + border = Border.THIN() + borderColor = Color.darkGray + horizontalAlign = HorizontalAlign.CENTER + verticalAlign = VerticalAlign.MIDDLE + backgroundColor = Color.decode("#f9fafb") + transparency = Transparency.OPAQUE + transparent = false + blankWhenNull = true + padding = 2 + pattern = '' + radius = 1 + rotation = Rotation.NONE + stretching = Stretching.NO_STRETCH + stretchWithOverflow = false + } + + detailStyle { + font = Font.ARIAL_MEDIUM + textColor = Color.black + borderTop = Border.NO_BORDER() + borderBottom = Border.THIN() + borderLeft = Border.NO_BORDER() + borderRight = Border.NO_BORDER() + borderColor = Color.LIGHT_GRAY + horizontalAlign = HorizontalAlign.LEFT + verticalAlign = VerticalAlign.MIDDLE + backgroundColor = Color.white + transparency = Transparency.OPAQUE + //transparent = false + blankWhenNull = true + padding = 4 + //pattern = '' + radius = 1 + rotation = Rotation.NONE + stretching = Stretching.NO_STRETCH + stretchWithOverflow = false + } + +} diff --git a/examples/sandbox-dynamic-jasper/grails-app/conf/application.groovy b/examples/sandbox-dynamic-jasper/grails-app/conf/application.groovy index f1a595d..6e43d21 100644 --- a/examples/sandbox-dynamic-jasper/grails-app/conf/application.groovy +++ b/examples/sandbox-dynamic-jasper/grails-app/conf/application.groovy @@ -6,4 +6,4 @@ jasper { } } -} \ No newline at end of file +} diff --git a/examples/sandbox-dynamic-jasper/grails-app/conf/logback.groovy b/examples/sandbox-dynamic-jasper/grails-app/conf/logback.groovy index dbc8f74..1288e8b 100644 --- a/examples/sandbox-dynamic-jasper/grails-app/conf/logback.groovy +++ b/examples/sandbox-dynamic-jasper/grails-app/conf/logback.groovy @@ -49,4 +49,4 @@ if (Environment.developmentMode && targetDir) { logger "grails.app.services.foobar", DEBUG,['STDOUT'] logger "org.grails.gsp.GroovyPageResourceLoader", DEBUG,['STDOUT'] logger "org.grails.gsp.io.DefaultGroovyPageLocator", DEBUG,['STDOUT'] -} \ No newline at end of file +} diff --git a/examples/sandbox-dynamic-jasper/grails-app/controllers/foo/NotNullPutAt.groovy b/examples/sandbox-dynamic-jasper/grails-app/controllers/foo/NotNullPutAt.groovy index 2dabb61..8e1fd1e 100644 --- a/examples/sandbox-dynamic-jasper/grails-app/controllers/foo/NotNullPutAt.groovy +++ b/examples/sandbox-dynamic-jasper/grails-app/controllers/foo/NotNullPutAt.groovy @@ -1,14 +1,14 @@ -/** - * @author Alejandro Gomez (alejandro.gomez@fdvsolutions.com) - * Date: 21-dic-2008 - * Time: 19:42:00 - */ -package foo -class NotNullPutAt { - - static void putAt(Object self, String prop, Object value) { - if (value != null && (!(value instanceof ConfigObject) || (value.size() > 0))) { - self.setProperty(prop, value) - } - } -} +/** + * @author Alejandro Gomez (alejandro.gomez@fdvsolutions.com) + * Date: 21-dic-2008 + * Time: 19:42:00 + */ +package foo +class NotNullPutAt { + + static void putAt(Object self, String prop, Object value) { + if (value != null && (!(value instanceof ConfigObject) || (value.size() > 0))) { + self.setProperty(prop, value) + } + } +} diff --git a/examples/sandbox-dynamic-jasper/grails-app/controllers/foo/ToStringCustomExpression.groovy b/examples/sandbox-dynamic-jasper/grails-app/controllers/foo/ToStringCustomExpression.groovy index f9fc00c..908b656 100644 --- a/examples/sandbox-dynamic-jasper/grails-app/controllers/foo/ToStringCustomExpression.groovy +++ b/examples/sandbox-dynamic-jasper/grails-app/controllers/foo/ToStringCustomExpression.groovy @@ -1,27 +1,27 @@ -package foo - -import ar.com.fdvs.dj.domain.CustomExpression - -/** - * @author Alejandro Gomez (alejandro.gomez@fdvsolutions.com) - * Date: 30-dic-2008 - * Time: 16:47:19 - */ - -class ToStringCustomExpression implements CustomExpression { - - def fieldName - - def ToStringCustomExpression(fieldName) { - this.fieldName = fieldName; - } - - public Object evaluate(Map fields, Map variables, Map parameters) { - fields[(fieldName)].toString() - } - - public String getClassName() { - String.name - } - -} \ No newline at end of file +package foo + +import ar.com.fdvs.dj.domain.CustomExpression + +/** + * @author Alejandro Gomez (alejandro.gomez@fdvsolutions.com) + * Date: 30-dic-2008 + * Time: 16:47:19 + */ + +class ToStringCustomExpression implements CustomExpression { + + def fieldName + + def ToStringCustomExpression(fieldName) { + this.fieldName = fieldName; + } + + public Object evaluate(Map fields, Map variables, Map parameters) { + fields[(fieldName)].toString() + } + + public String getClassName() { + String.name + } + +} diff --git a/examples/sandbox-dynamic-jasper/grails-app/domain/foo/Bills.groovy b/examples/sandbox-dynamic-jasper/grails-app/domain/foo/Bills.groovy index d657aac..645738f 100644 --- a/examples/sandbox-dynamic-jasper/grails-app/domain/foo/Bills.groovy +++ b/examples/sandbox-dynamic-jasper/grails-app/domain/foo/Bills.groovy @@ -1,8 +1,5 @@ package foo -import ar.com.fdvs.dj.core.layout.HorizontalBandAlignment -import ar.com.fdvs.dj.domain.AutoText - class Bills { Customer customer diff --git a/examples/sandbox-dynamic-jasper/grails-app/init/Application.groovy b/examples/sandbox-dynamic-jasper/grails-app/init/Application.groovy index d1a2484..27fb92b 100644 --- a/examples/sandbox-dynamic-jasper/grails-app/init/Application.groovy +++ b/examples/sandbox-dynamic-jasper/grails-app/init/Application.groovy @@ -7,4 +7,4 @@ class Application extends GrailsAutoConfiguration { static void main(String[] args) { GrailsApp.run(Application, args) } -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties index 9755c12..13303a0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,36 @@ -grailsVersion=3.3.2 -gormVersion=6.1.9.BUILD-SNAPSHOT -gradleWrapperVersion=3.5 -projectVersion=3.1.1-SNAPSHOT +grailsVersion=3.3.9 +gormVersion=6.1.11.RELEASE +grailsViewsVersion=1.2.3 +viewsVersion=1.2.6 +gradleWrapperVersion=4.6 +# common settings used for doc generation links, publishing docs to gh-pages and maven/bintray publish title=Jasper reports Grails Plugin -projectDesc=Jasper reports Grails Plugin -projectUrl=https://github.com/yakworks/grails-jasper-reports -githubSlug=yakworks/grails-jasper-reports +description=Jasper reports Grails Plugin +author=9ci Inc +# Bintray and/or artifactory/maven settings +group=org.grails.plugins +gitHubSlug=yakworks/grails-jasper-reports +gitConfigUser=9cibot +gitConfigEmail=9cibot@9ci.com + +#is default matches 'master', 10.0.x, 'release/2.x', 'release/3.x', etc. +gitReleasableBranch="master|release/.+" + +enableDocsPublish=false +# bintray, don't set bintrayRepo to use standard maven/artifactory to publish +bintrayOrg=9ci +bintrayRepo=grails-plugins +#mavenRepoUrl=http://repo.9ci.com/grails-plugins +mavenSnapshotUrl=http://repo.9ci.com/oss-snapshots + +# Spotless props +license=Proprietary +#licenseHeader=/* Copyright \$YEAR. 9ci Inc. Licensed under the Apache License, Version 2.0 */ +developers = {"basejump": "Joshua Burnett", "snimavat": "Sudhir Nimavat"} + +# versions +versionHibernate=5.2.16.Final +versionBuildTestData=3.3.+ +versionViews=1.2.7 diff --git a/gradle/codenarck-rules.groovy b/gradle/codenarck-rules.groovy deleted file mode 100644 index 9af1ae8..0000000 --- a/gradle/codenarck-rules.groovy +++ /dev/null @@ -1,386 +0,0 @@ -ruleset { - - // rulesets/basic.xml - AssertWithinFinallyBlock - AssignmentInConditional - BigDecimalInstantiation - BitwiseOperatorInConditional - BooleanGetBoolean - BrokenNullCheck - BrokenOddnessCheck - ClassForName - ComparisonOfTwoConstants - ComparisonWithSelf - ConstantAssertExpression - ConstantIfExpression - ConstantTernaryExpression - DeadCode - DoubleNegative - DuplicateCaseStatement - DuplicateMapKey - DuplicateSetValue - EmptyCatchBlock - 'EmptyClass' doNotApplyToFilesMatching: '.*Spec.groovy' - EmptyElseBlock - EmptyFinallyBlock - EmptyForStatement - EmptyIfStatement - EmptyInstanceInitializer - EmptyMethod - EmptyStaticInitializer - EmptySwitchStatement - EmptySynchronizedStatement - EmptyTryBlock - EmptyWhileStatement - EqualsAndHashCode - EqualsOverloaded - ExplicitGarbageCollection - ForLoopShouldBeWhileLoop - HardCodedWindowsFileSeparator - HardCodedWindowsRootDirectory - IntegerGetInteger - MultipleUnaryOperators - RandomDoubleCoercedToZero - RemoveAllOnSelf - ReturnFromFinallyBlock - ThrowExceptionFromFinallyBlock - - // rulesets/braces.xml - ElseBlockBraces - ForStatementBraces - //IfStatementBraces - WhileStatementBraces - - // rulesets/concurrency.xml - BusyWait - DoubleCheckedLocking - InconsistentPropertyLocking - InconsistentPropertySynchronization - NestedSynchronization - StaticCalendarField - StaticConnection - StaticDateFormatField - StaticMatcherField - StaticSimpleDateFormatField - SynchronizedMethod - SynchronizedOnBoxedPrimitive - SynchronizedOnGetClass - SynchronizedOnReentrantLock - SynchronizedOnString - SynchronizedOnThis - SynchronizedReadObjectMethod - SystemRunFinalizersOnExit - ThisReferenceEscapesConstructor - ThreadGroup - ThreadLocalNotStaticFinal - ThreadYield - UseOfNotifyMethod - VolatileArrayField - VolatileLongOrDoubleField - WaitOutsideOfWhileLoop - - // rulesets/convention.xml - ConfusingTernary - //CouldBeElvis - HashtableIsObsolete - IfStatementCouldBeTernary - InvertedIfElse - LongLiteralWithLowerCaseL - 'NoDef' doNotApplyToFilesMatching: '.*Spec.groovy|.*Controller.groovy|.*GrailsPlugin.groovy' - //ParameterReassignment - TernaryCouldBeElvis - VectorIsObsolete - - // rulesets/design.xml - 'AbstractClassWithPublicConstructor' enabled: false - AbstractClassWithoutAbstractMethod - BooleanMethodReturnsNull - //BuilderMethodWithSideEffects - CloneableWithoutClone - CloseWithoutCloseable - CompareToWithoutComparable - ConstantsOnlyInterface - EmptyMethodInAbstractClass - FinalClassWithProtectedMember - ImplementationAsType - 'Instanceof' enabled: false - LocaleSetDefault - //NestedForLoop - 'PrivateFieldCouldBeFinal' enabled: false - PublicInstanceField - ReturnsNullInsteadOfEmptyArray - ReturnsNullInsteadOfEmptyCollection - //SimpleDateFormatMissingLocale - StatelessSingleton - ToStringReturnsNull - - // rulesets/dry.xml -// DuplicateListLiteral -// DuplicateMapLiteral -// DuplicateNumberLiteral -// DuplicateStringLiteral - - // rulesets/enhanced.xml - //CloneWithoutCloneable - //JUnitAssertEqualsConstantActualValue - //UnsafeImplementationAsMap - - // rulesets/exceptions.xml - CatchArrayIndexOutOfBoundsException - CatchError - CatchException - CatchIllegalMonitorStateException - CatchIndexOutOfBoundsException - CatchNullPointerException - CatchRuntimeException - CatchThrowable - ConfusingClassNamedException - ExceptionExtendsError - ExceptionExtendsThrowable - ExceptionNotThrown - MissingNewInThrowStatement - ReturnNullFromCatchBlock - SwallowThreadDeath - ThrowError - ThrowException - ThrowNullPointerException - ThrowRuntimeException - ThrowThrowable - - // rulesets/formatting.xml - BlankLineBeforePackage - BracesForClass - BracesForForLoop - BracesForIfElse - BracesForMethod - BracesForTryCatchFinally - //ClassJavadoc - ClosureStatementOnOpeningLineOfMultipleLineClosure - ConsecutiveBlankLines - //FileEndsWithoutNewline - //'LineLength' doNotApplyToFilesMatching: '*Spec.groovy' - MissingBlankLineAfterImports - MissingBlankLineAfterPackage - //SpaceAfterCatch - //SpaceAfterFor - //SpaceAfterIf - //SpaceAfterSwitch - //SpaceAfterWhile - //SpaceAroundClosureArrow - //SpaceAroundMapEntryColon - //SpaceAroundOperator - //SpaceAfterClosingBrace - SpaceAfterComma - //SpaceAfterOpeningBrace - SpaceAfterSemicolon - //SpaceBeforeClosingBrace - //SpaceBeforeOpeningBrace - //TrailingWhitespace - - // rulesets/generic.xml - IllegalClassMember - IllegalClassReference - IllegalPackageReference - IllegalRegex - IllegalString - IllegalSubclass - RequiredRegex - RequiredString - StatelessClass - - // rulesets/groovyism.xml - AssignCollectionSort - AssignCollectionUnique - ClosureAsLastMethodParameter - CollectAllIsDeprecated - ConfusingMultipleReturns - ExplicitArrayListInstantiation - ExplicitCallToAndMethod - ExplicitCallToCompareToMethod - ExplicitCallToDivMethod - ExplicitCallToEqualsMethod - ExplicitCallToGetAtMethod - ExplicitCallToLeftShiftMethod - ExplicitCallToMinusMethod - ExplicitCallToModMethod - ExplicitCallToMultiplyMethod - ExplicitCallToOrMethod - ExplicitCallToPlusMethod - ExplicitCallToPowerMethod - ExplicitCallToRightShiftMethod - ExplicitCallToXorMethod - ExplicitHashMapInstantiation - ExplicitHashSetInstantiation - ExplicitLinkedHashMapInstantiation - ExplicitLinkedListInstantiation - ExplicitStackInstantiation - ExplicitTreeSetInstantiation - GStringAsMapKey - GStringExpressionWithinString - //GetterMethodCouldBeProperty - GroovyLangImmutable - UseCollectMany - UseCollectNested - - // rulesets/imports.xml - DuplicateImport - ImportFromSamePackage - ImportFromSunPackages - //MisorderedStaticImports - //'NoWildcardImports' doNotApplyToFilesMatching: '.*Spec.groovy' - UnnecessaryGroovyImport - UnusedImport - - // rulesets/jdbc.xml - DirectConnectionManagement - JdbcConnectionReference - JdbcResultSetReference - JdbcStatementReference - - // rulesets/junit.xml - ChainedTest - CoupledTestCase - JUnitAssertAlwaysFails - JUnitAssertAlwaysSucceeds - JUnitFailWithoutMessage - JUnitLostTest - JUnitPublicField - JUnitPublicNonTestMethod - //JUnitPublicProperty - JUnitSetUpCallsSuper - JUnitStyleAssertions - JUnitTearDownCallsSuper - JUnitTestMethodWithoutAssert - JUnitUnnecessarySetUp - JUnitUnnecessaryTearDown - JUnitUnnecessaryThrowsException - SpockIgnoreRestUsed - UnnecessaryFail - UseAssertEqualsInsteadOfAssertTrue - UseAssertFalseInsteadOfNegation - UseAssertNullInsteadOfAssertEquals - UseAssertSameInsteadOfAssertTrue - UseAssertTrueInsteadOfAssertEquals - UseAssertTrueInsteadOfNegation - - // rulesets/logging.xml - LoggerForDifferentClass - LoggerWithWrongModifiers - LoggingSwallowsStacktrace - MultipleLoggers - PrintStackTrace - //Println - SystemErrPrint - SystemOutPrint - - // rulesets/naming.xml - AbstractClassName - ClassName - ClassNameSameAsFilename - //ConfusingMethodName - //'FactoryMethodName' doNotApplyToFilesMatching: '.*Spec.groovy' - FieldName - InterfaceName - 'MethodName' doNotApplyToFilesMatching: '.*Spec.groovy' - ObjectOverrideMisspelledMethodName - PackageName - PackageNameMatchesFilePath - ParameterName - PropertyName - VariableName - - // rulesets/security.xml - FileCreateTempFile - InsecureRandom - 'JavaIoPackageAccess' enabled: false - NonFinalPublicField - NonFinalSubclassOfSensitiveInterface - ObjectFinalize - PublicFinalizeMethod - SystemExit - UnsafeArrayDeclaration - - // rulesets/serialization.xml - EnumCustomSerializationIgnored - SerialPersistentFields - SerialVersionUID - 'SerializableClassMustDefineSerialVersionUID' enabled: false - - // rulesets/size.xml - AbcComplexity // DEPRECATED: Use the AbcMetric rule instead. Requires the GMetrics jar - 'AbcMetric' doNotApplyToFilesMatching: '.*Spec.groovy' // Requires the GMetrics jar - ClassSize - //CrapMetric // Requires the GMetrics jar and a Cobertura coverage file - //CyclomaticComplexity - MethodCount - 'MethodSize' doNotApplyToFilesMatching: '.*Spec.groovy' - NestedBlockDepth - //'ParameterCount' maxParameters: 6 - - // rulesets/unnecessary.xml - AddEmptyString - ConsecutiveLiteralAppends - //ConsecutiveStringConcatenation - UnnecessaryBigDecimalInstantiation - UnnecessaryBigIntegerInstantiation - 'UnnecessaryBooleanExpression' doNotApplyToFilesMatching: '.*Spec.groovy' - UnnecessaryBooleanInstantiation - UnnecessaryCallForLastElement - UnnecessaryCallToSubstring - UnnecessaryCast - UnnecessaryCatchBlock - UnnecessaryCollectCall - UnnecessaryCollectionCall - UnnecessaryConstructor - UnnecessaryDefInFieldDeclaration - //UnnecessaryDefInMethodDeclaration - UnnecessaryDefInVariableDeclaration - //UnnecessaryDotClass - UnnecessaryDoubleInstantiation - UnnecessaryElseStatement - UnnecessaryFinalOnPrivateMethod - UnnecessaryFloatInstantiation - //UnnecessaryGString - //UnnecessaryGetter - UnnecessaryIfStatement - UnnecessaryInstanceOfCheck - UnnecessaryInstantiationToGetClass - UnnecessaryIntegerInstantiation - UnnecessaryLongInstantiation - UnnecessaryModOne - UnnecessaryNullCheck - UnnecessaryNullCheckBeforeInstanceOf - 'UnnecessaryObjectReferences' doNotApplyToFilesMatching: '.*Spec.groovy' - UnnecessaryOverridingMethod - UnnecessaryPackageReference - UnnecessaryParenthesesForMethodCallWithClosure - //UnnecessaryPublicModifier - //UnnecessaryReturnKeyword - UnnecessarySafeNavigationOperator - UnnecessarySelfAssignment - UnnecessarySemicolon - UnnecessaryStringInstantiation - //UnnecessarySubstring - UnnecessaryTernaryExpression - //UnnecessaryToString - UnnecessaryTransientModifier - - // rulesets/unused.xml - UnusedArray - 'UnusedMethodParameter' enabled: false - UnusedObject - UnusedPrivateField - UnusedPrivateMethod - UnusedPrivateMethodParameter - //UnusedVariable - - // Formatting - NoTabCharacter - - ruleset('rulesets/codenarc-extra.xml') { - CompileStatic { - //doNotApplyToClassNames = '*Spec,*Test,.*GrailsPlugin,Application' - doNotApplyToFilesMatching = ".*/src/test/.*|.*GrailsPlugin.groovy|.*Application.groovy|.*BootStrap.groovy" - } - } -} diff --git a/gradle/common-publishing.gradle b/gradle/common-publishing.gradle deleted file mode 100644 index 3056bb4..0000000 --- a/gradle/common-publishing.gradle +++ /dev/null @@ -1,45 +0,0 @@ - - -apply plugin:"org.grails.grails-plugin-publish" - -String binTrayUser = System.getenv("BINTRAY_USER") ?: project.hasProperty('bintrayUser') ? project.bintrayUser : null -String binTrayKey = System.getenv("BINTRAY_KEY") ?: project.hasProperty('bintrayKey') ? project.bintrayKey : null -String artifactoryUsername = System.getenv("ARTIFACTORY_USER") ?: project.hasProperty('artifactoryUsername') ? project.artifactoryUsername : null -String artifactoryPassword = System.getenv("ARTIFACTORY_PASSWORD") ?: project.hasProperty('artifactoryPassword') ? project.artifactoryPassword : null - -if(binTrayUser && binTrayKey) { - grailsPublish { - user = binTrayUser - key = binTrayKey - - desc = "${project.title} - ${project.projectDesc}".toString() - - developers = [joshuaB: 'Joshua B', snimavat: "Sudhir Nimavat"] - githubSlug = "${project.githubSlug}" - issueTrackerUrl = "https://github.com/${project.githubSlug}/issues" - vcsUrl = "https://github.com/${project.githubSlug}" - - license { - name = 'Apache-2.0' - } - - title = project.title - userOrg = '9ci' - repo = 'grails-plugins' - } -} - -if(isSnapshot && artifactoryUsername && artifactoryPassword) { - publishing { - println "SNAPSHOT - " + project.name + ":" + version.toString() - repositories { - maven { - url "http://repo.9ci.com/oss-snapshots" - credentials { - username artifactoryUsername - password artifactoryPassword - } - } - } - } -} \ No newline at end of file diff --git a/gradle/shipkit.gradle b/gradle/shipkit.gradle new file mode 100644 index 0000000..d2c50e8 --- /dev/null +++ b/gradle/shipkit.gradle @@ -0,0 +1,8 @@ +shipkit { + git.user = gitConfigUser + git.email = gitConfigEmail + gitHub.repository = gitHubSlug + gitHub.readOnlyAuthToken = "76826c9ec886612f504d12fd4268b16721c4f85d" + gitHub.writeAuthToken = System.getenv("GRGIT_USER") ?: System.getenv("GH_WRITE_TOKEN") ?: project.findProperty("gitHubToken") + //releaseNotes.publicationRepository = "$mavenRepoUrl/org.grail.plugins.gradle/" +} diff --git a/gradlew b/gradlew index 4453cce..cccdd3d 100755 --- a/gradlew +++ b/gradlew @@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -155,7 +155,7 @@ if $cygwin ; then fi # Escape application args -save ( ) { +save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } diff --git a/grailsw b/grailsw deleted file mode 100755 index c2c921c..0000000 --- a/grailsw +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Grails start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRAILS_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-XX:+TieredCompilation" "-XX:TieredStopAtLevel=1" "-XX:CICompilerCount=3"' - - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -JAR_PATH=$APP_HOME/grails-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRAILS_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRAILS_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRAILS_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRAILS_OPTS - -exec "$JAVACMD" -jar "${JVM_OPTS[@]}" "$JAR_PATH" "$@" diff --git a/grailsw.bat b/grailsw.bat deleted file mode 100755 index c48c384..0000000 --- a/grailsw.bat +++ /dev/null @@ -1,89 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Grails startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRAILS_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-XX:+TieredCompilation" "-XX:TieredStopAtLevel=1" "-XX:CICompilerCount=3" - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line -set JAR_PATH=%APP_HOME%/grails-wrapper.jar - -@rem Execute Grails -"%JAVA_EXE%" -jar %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRAILS_OPTS% %JAR_PATH% %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRAILS_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRAILS_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/plugin/build.gradle b/plugin/build.gradle index ff9e2ae..4a4b0b7 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -1,5 +1,14 @@ +apply plugin: 'yakworks.grails-plugin' +apply plugin: "org.grails.grails-gsp" + dependencies { + profile "org.grails.profiles:web-plugin" + compile "org.springframework.boot:spring-boot-starter-actuator" + provided "org.springframework.boot:spring-boot-starter-tomcat" + + provided "org.grails:grails-plugin-services" + provided "org.grails:grails-plugin-domain-class" def poiVersion='3.9' compile 'org.apache.poi:poi:'+poiVersion @@ -28,7 +37,7 @@ dependencies { exclude module: 'batik-bridge' //don't need the barcode stuff } - compile 'org.grails.plugins:view-tools:1.1' + compile 'org.grails.plugins:view-tools:1.2-SNAPSHOT' testCompile "org.grails:grails-plugin-testing" } @@ -38,3 +47,32 @@ bootRun { } // enable if you wish to package this plugin as a standalone application bootRepackage.enabled = false + +ext.codenarcRuleset= ''' + getRule('LineLength').enabled = false + getRule('CyclomaticComplexity').enabled = false + getRule('NoWildcardImports').enabled = false + getRule('UnnecessaryDotClass').enabled = false + getRule('CatchException').enabled = false + getRule('AbcMetric').enabled = false + getRule('MethodSize').enabled = false + getRule('InvertedIfElse').enabled = false + //getRule('Println').enabled = false +''' + + +codenarcMain { + exclude '**/BootStrap.groovy' + exclude '**/GormToolsGrailsPlugin.groovy' + exclude '**/GormToolsPluginHelper.groovy' +} + +codenarcTest { + exclude '**/*' + ignoreFailures = true +} + +codenarcIntegrationTest { + exclude '**/*' + ignoreFailures = true +} diff --git a/plugin/grails-app/conf/JasperReportsDefaultConfig.groovy b/plugin/grails-app/conf/JasperReportsDefaultConfig.groovy index 8b421c5..3c538f8 100644 --- a/plugin/grails-app/conf/JasperReportsDefaultConfig.groovy +++ b/plugin/grails-app/conf/JasperReportsDefaultConfig.groovy @@ -57,4 +57,3 @@ reporting { localizedLookup = false } } - diff --git a/plugin/grails-app/init/nine/jasper/Application.groovy b/plugin/grails-app/init/nine/jasper/Application.groovy index 3687d02..6a5bcd4 100644 --- a/plugin/grails-app/init/nine/jasper/Application.groovy +++ b/plugin/grails-app/init/nine/jasper/Application.groovy @@ -9,4 +9,4 @@ class Application extends GrailsAutoConfiguration { static void main(String[] args) { GrailsApp.run(Application, args) } -} \ No newline at end of file +} diff --git a/plugin/grails-app/services/nine/jasper/JasperService.groovy b/plugin/grails-app/services/nine/jasper/JasperService.groovy index be1c66c..e12938c 100644 --- a/plugin/grails-app/services/nine/jasper/JasperService.groovy +++ b/plugin/grails-app/services/nine/jasper/JasperService.groovy @@ -1,5 +1,6 @@ package nine.jasper +import groovy.transform.CompileDynamic import net.sf.jasperreports.engine.JasperReport import nine.jasper.spring.JasperView import nine.jasper.spring.JasperViewResolver @@ -8,47 +9,48 @@ import nine.jasper.spring.JasperReportDef /** * @author Sudhir Nimavat */ +@CompileDynamic class JasperService { - static transactional = false + static transactional = false - JasperViewResolver jasperViewResolver + JasperViewResolver jasperViewResolver - /** - * Returns JasperView for given report file name - * - * @param name Report file name - * @return JasperView - */ - public JasperView getView(String name) { - return (JasperView)jasperViewResolver.resolveViewName(name, null) - } + /** + * Returns JasperView for given report file name + * + * @param name Report file name + * @return JasperView + */ + public JasperView getView(String name) { + return (JasperView) jasperViewResolver.resolveViewName(name, null) + } - /** - * Returns JasperReport instance for given report file name - * - * @param name Report file name - * @return JasperReport - */ - public JasperReport getJasperReport(String name) { - return getView(name).report - } + /** + * Returns JasperReport instance for given report file name + * + * @param name Report file name + * @return JasperReport + */ + public JasperReport getJasperReport(String name) { + return getView(name).report + } - /** - * Renders the jasper report for given JasperReportDef and returns ByteArrayOutputStream - * - * @param opts JasperReportDef - * @return ByteArrayOutputStream - */ - public ByteArrayOutputStream generateReport(JasperReportDef opts) { - ByteArrayOutputStream out = new ByteArrayOutputStream() - JasperView view = getView(opts.name) - Map model = [:] - model.putAll(opts.parameters) - model.format = opts.fileFormat - if(opts.reportData != null) model.data = opts.reportData - view.render(model, out) - out.flush() - return out - } + /** + * Renders the jasper report for given JasperReportDef and returns ByteArrayOutputStream + * + * @param opts JasperReportDef + * @return ByteArrayOutputStream + */ + public ByteArrayOutputStream generateReport(JasperReportDef opts) { + ByteArrayOutputStream out = new ByteArrayOutputStream() + JasperView view = getView(opts.name) + Map model = [:] + model.putAll(opts.parameters) + model.format = opts.fileFormat + if (opts.reportData != null) model.data = opts.reportData + view.render(model, out) + out.flush() + return out + } } diff --git a/plugin/grails-app/services/nine/jasper/JasperViewService.groovy b/plugin/grails-app/services/nine/jasper/JasperViewService.groovy index 16ccbb8..3227824 100644 --- a/plugin/grails-app/services/nine/jasper/JasperViewService.groovy +++ b/plugin/grails-app/services/nine/jasper/JasperViewService.groovy @@ -24,34 +24,34 @@ class JasperViewService { LocaleResolver localeResolver JasperViewResolver jasperViewResolver - View getView(String viewName, Locale locale = null){ + View getView(String viewName, Locale locale = null) { locale = locale ?: getLocale() //GrailsWebEnvironment.bindRequestIfNull(grailsApplication.mainContext) - return jasperViewResolver.resolveViewName( viewName, locale) + return jasperViewResolver.resolveViewName(viewName, locale) } /** * Calls getView to grab the jasper template and and then passes to render(view,model...) */ - Writer render(String viewName , Map model, Writer writer = new CharArrayWriter()){ + Writer render(String viewName, Map model, Writer writer = new CharArrayWriter()) { //GrailsWebEnvironment.bindRequestIfNull(grailsApplication.mainContext, writer) -- xxx why do we need this ? - JasperView view = (JasperView)jasperViewResolver.resolveViewName( viewName, getLocale()) + JasperView view = (JasperView) jasperViewResolver.resolveViewName(viewName, getLocale()) if (!view) { - throw new IllegalArgumentException("The ftl view [${viewName}] could not be found" ) + throw new IllegalArgumentException("The ftl view [${viewName}] could not be found") } - render( view, model, writer) + render(view, model, writer) } /** * processes the jasper report template in the View. * sets the plugin thread local if passed in and bind a request if none exists before processing. * - * @param view JasperView that holds the template + * @param view JasperView that holds the template * @param model the hash model the should be passed into the freemarker tempalate * @param writer (optional) a writer if you have one. a CharArrayWriter will be created by default. * @return the writer that was passed in. */ - Writer render(JasperView view , Map model, Writer writer = new CharArrayWriter()){ + Writer render(JasperView view, Map model, Writer writer = new CharArrayWriter()) { if (!view) { throw new IllegalArgumentException("The 'view' argument cannot be null") @@ -62,7 +62,7 @@ class JasperViewService { int mapSize = attributesMap.size() + (model != null ? model.size() : 0) Map mergedModel = new HashMap(mapSize) mergedModel.putAll(attributesMap) - if (model) mergedModel.putAll(model) + if (model) mergedModel.putAll(model) ///GrailsWebEnvironment.bindRequestIfNull(grailsApplication.mainContext, writer) XXX why do we need this ? //view render return writer @@ -77,7 +77,7 @@ class JasperViewService { def locale def request = GrailsWebRequest.lookup()?.currentRequest locale = localeResolver?.resolveLocale(request) - if(locale == null) { + if (locale == null) { locale = Locale.default } return locale diff --git a/plugin/grails-app/services/nine/jasper/dynamic/DynamicReportsService.groovy b/plugin/grails-app/services/nine/jasper/dynamic/DynamicReportsService.groovy index fe3d86c..4474644 100644 --- a/plugin/grails-app/services/nine/jasper/dynamic/DynamicReportsService.groovy +++ b/plugin/grails-app/services/nine/jasper/dynamic/DynamicReportsService.groovy @@ -33,14 +33,15 @@ class DynamicReportsService { GrailsApplication grailsApplication - JasperReportBuilder buildDynamicReport(Map reportCfg){ + JasperReportBuilder buildDynamicReport(Map reportCfg) { PersistentEntity domainClass = DomainMetaUtils.findDomainClass(reportCfg.domain) //TODO blow logical error here is domainClass can't be found buildDynamicReport(domainClass, reportCfg) } + JasperReportBuilder buildDynamicReport(PersistentEntity domainClass, Map reportCfg, Map params = null) { - println "doReport with $params" + log.debug "doReport with $params" //TODO do some basic validation on reportCfg. maybe even setup domains for them List fields = reportCfg["fields"] as List @@ -48,29 +49,29 @@ class DynamicReportsService { //?: getPropertyValue(domainClass.clazz, 'reportColumns') ?: domainClass.properties.name - ['id', 'version'] JasperReportBuilder jrb = new JasperReportBuilder() - .title(TemplateStyles.createTitleComponent("Group")) - .setTemplate(TemplateStyles.reportTemplate) - .templateStyles(TemplateStyles.loadStyles(grailsApplication.mainContext)) + .title(TemplateStyles.createTitleComponent("Group")) + .setTemplate(TemplateStyles.reportTemplate) + .templateStyles(TemplateStyles.loadStyles(grailsApplication.mainContext)) // def res = grailsApplication.mainContext.getResource("classpath:nine/jasper/DefaultTemplate.jrxml") // jrb.setTemplateDesign(res.inputStream) - if(reportCfg.highlightDetailOddRows) { + if (reportCfg.highlightDetailOddRows) { jrb.highlightDetailOddRows().setDetailOddRowStyle(TemplateStyles.oddRowStyle) } - if(reportCfg.showGridLines) { + if (reportCfg.showGridLines) { jrb.setColumnStyle(TemplateStyles.columnWithGridLines)//StyleTemplates.columnStyleWithGridLines)// } - if(reportCfg.tableOfContents) { + if (reportCfg.tableOfContents) { jrb.tableOfContents() } - if(reportCfg.ignorePagination){ + if (reportCfg.ignorePagination) { jrb.ignorePagination() - }else{ + } else { jrb.pageFooter(TemplateStyles.createFooter()) } - if(reportCfg.landscape){ + if (reportCfg.landscape) { jrb.setPageFormat(PageType.LETTER, PageOrientation.LANDSCAPE) } @@ -78,29 +79,28 @@ class DynamicReportsService { //.sortBy(dateColumn, invoiceColumn) //Column setups - Map fieldMetaMap = DomainMetaUtils.getFieldMetadata(domainClass, fields, reportCfg.columnTitles) - populateColumnBuilders(fieldMetaMap,jrb) + Map fieldMetaMap = DomainMetaUtils.getFieldMetadata(domainClass, fields, reportCfg.columnTitles) + populateColumnBuilders(fieldMetaMap, jrb) List columnBuilderList = fieldMetaMap.values()*.builder.toList() jrb.columns(*columnBuilderList) //Groups - Map groupBuilders = buildGroupBands(fieldMetaMap, reportCfg) - groupBuilders.eachWithIndex{k,v,i-> + Map groupBuilders = buildGroupBands(fieldMetaMap, reportCfg) + groupBuilders.eachWithIndex { k, v, i -> jrb.groupBy(v.builder.headerWithSubtotal()).subtotalsAtGroupFooter(v.builder, *v.subtotalBuilders) } - if(reportCfg.columnHeaderInFirstGroup) jrb.setShowColumnTitle(false) - if(reportCfg.showTableOfContents) jrb.tableOfContents() + if (reportCfg.columnHeaderInFirstGroup) jrb.setShowColumnTitle(false) + if (reportCfg.showTableOfContents) jrb.tableOfContents() return jrb } - Collection createDataSource(PersistentEntity domainClass, List groupFields) { List results if (groupFields) { def c = domainClass.javaClass.createCriteria() - results = c.list{ + results = c.list { orderNested(groupFields).call() } //recs = domainClass.clazz.findAll("from $domainClass.clazz.name as s order by ${groupFields.join(',')}") @@ -116,19 +116,19 @@ class DynamicReportsService { * @param fieldMap * @return the same map ref populated */ - Map populateColumnBuilders(Map fieldMap,JasperReportBuilder jrb){ + Map populateColumnBuilders(Map fieldMap, JasperReportBuilder jrb) { //Map drCols = [:] fieldMap.each { /*key*/ String field, /*value*/ FieldMetadata fld -> ColumnBuilder colb colb = Columns.column(field, DataTypes.detectType(fld.typeClass)).setAnchorName(field) - colb.setWidth(fld.width == null?4:fld.width) + colb.setWidth(fld.width == null ? 4 : fld.width) //link symbols , 221e,260d, 2709 is email, 270e is pencil - HyperLinkBuilder link = hyperLink(jrExp('"https://www.google.com/search?q=" + $F{' + field +'}')) + HyperLinkBuilder link = hyperLink(jrExp('"https://www.google.com/search?q=" + $F{' + field + '}')) colb.setHyperLink(link) - if(fld.isBooleanType()){ - jrb.addField(field,Boolean.class) //drb.field(field,Boolean.class) + if (fld.isBooleanType()) { + jrb.addField(field, Boolean.class) //drb.field(field,Boolean.class) //? (char)0x2611 : (char)0x2610") //<- see http://dejavu.sourceforge.net/samples/DejaVuSans.pdf for more options JasperExpression bool = jrExp('$F{' + field + '} ? (char)0x2713 : ""') @@ -137,7 +137,7 @@ class DynamicReportsService { //def sb = new StyleBuilder() //sb.object.parentStyle = jrb.object.columnStyle //colb.style = sb.bold()//.setFontSize(18) - colb.setWidth(fld.width == null?1:fld.width) + colb.setWidth(fld.width == null ? 1 : fld.width) } colb.setTitle(jrText(fld.title)) @@ -146,32 +146,29 @@ class DynamicReportsService { return fieldMap } - Map buildGroupBands(Map fieldMetaMap, Map config ){ + Map buildGroupBands(Map fieldMetaMap, Map config) { - Map groups = [:] + Map groups = [:] int grpSize = (config.groups as Map).size() config.groups.eachWithIndex { String field, Integer index -> - ColumnGroupBuilder group = Groups.group("Group_$field",fieldMetaMap[field].builder as ValueColumnBuilder) - boolean isLastOrSingleGroup = (grpSize == index+1) + ColumnGroupBuilder group = Groups.group("Group_$field", fieldMetaMap[field].builder as ValueColumnBuilder) + boolean isLastOrSingleGroup = (grpSize == index + 1) group.setPadding(3) if (index == 0) { group.setHeaderLayout(GroupHeaderLayout.VALUE) - if(config?.columnHeaderInFirstGroup) group.showColumnHeaderAndFooter() + if (config?.columnHeaderInFirstGroup) group.showColumnHeaderAndFooter() group.setStyle(TemplateStyles.group) group.setFooterStyle(TemplateStyles.group) - if(config.footerLabels){ - } - } else if (index == 1){ + } else if (index == 1) { //group.setHeaderLayout(GroupHeaderLayout.VALUE) group.setStyle(TemplateStyles.groupL2) group.setHeaderStyle(TemplateStyles.groupHeaderL2) group.setFooterStyle(TemplateStyles.groupFooterL2) //group.setPadding(3) //group.showColumnHeaderAndFooter - } - else{ + } else { group.setStyle(TemplateStyles.groupL3) group.setHeaderStyle(TemplateStyles.groupHeaderL3) group.setFooterStyle(TemplateStyles.groupFooterL3) @@ -199,14 +196,14 @@ class DynamicReportsService { // group.addFooterComponent(comp) //don't add it to the last group by default or if there is only 1 group - if(config.groupTotalLabels && sbtList && !isLastOrSingleGroup) { + if (config.groupTotalLabels && sbtList && !isLastOrSingleGroup) { //just add it to the first one //sbtList[0].setLabel("${fieldMetaMap[field].title} Totals").setLabelPosition(Position.LEFT); - JasperExpression label = jrExp("\$F{" + field + "} + \" Total\"", String.class); + JasperExpression label = jrExp("\$F{" + field + "} + \" Total\"", String.class) //sbtList.add drb.sbt.first(label,fieldMetaMap[config.groupTotalLabels].builder) group.setFooterBackgroundComponent( - Components.text(label).setStyle(TemplateStyles.subtotal) + Components.text(label).setStyle(TemplateStyles.subtotal) ) } @@ -218,7 +215,7 @@ class DynamicReportsService { return groups } - + @SuppressWarnings(['UnusedPrivateMethod']) private Map loadConfig() { def config = grailsApplication.config GroovyClassLoader classLoader = new GroovyClassLoader(getClass().classLoader) @@ -231,11 +228,11 @@ class DynamicReportsService { return new ConfigSlurper(GrailsUtil.environment).parse(new Properties()).merge(config.dynamicJasper) } - def getPropertyValue(def clazz, def propertyName) { + def getPropertyValue(Class clazz, String propertyName) { clazz.metaClass.hasProperty(clazz, propertyName)?.getProperty(clazz) } - def setPropertyIfNotNull(def target, def propertyName, def value) { + def setPropertyIfNotNull(Object target, String propertyName, Object value) { if (value != null && (!(value instanceof ConfigObject) || !(value.isEmpty()))) { target[propertyName] = value } @@ -250,7 +247,7 @@ class DynamicReportsService { * @return the expression */ public JasperExpression jrText(String text) { - return Expressions.jasperSyntaxText(text); + return Expressions.jasperSyntaxText(text) } /** @@ -262,7 +259,7 @@ class DynamicReportsService { * @return the expression */ public JasperExpression jrExp(String expression, Class valueClass) { - return Expressions.jasperSyntax(expression, valueClass); + return Expressions.jasperSyntax(expression, valueClass) } /** @@ -274,8 +271,7 @@ class DynamicReportsService { */ @SuppressWarnings("rawtypes") public JasperExpression jrExp(String expression) { - return Expressions.jasperSyntax(expression); + return Expressions.jasperSyntax(expression) } - } diff --git a/plugin/src/main/groovy/nine/jasper/JRDataSourceJDBC.groovy b/plugin/src/main/groovy/nine/jasper/JRDataSourceJDBC.groovy index 2eb2b79..d54922a 100644 --- a/plugin/src/main/groovy/nine/jasper/JRDataSourceJDBC.groovy +++ b/plugin/src/main/groovy/nine/jasper/JRDataSourceJDBC.groovy @@ -11,12 +11,12 @@ import javax.sql.DataSource * Simple container class so we can pass the jdbc connection around as a JRDataSource */ @CompileStatic -class JRDataSourceJDBC implements JRDataSource{ +class JRDataSourceJDBC implements JRDataSource { DataSource dataSource public JRDataSourceJDBC(DataSource dataSource) { - this.dataSource = dataSource; + this.dataSource = dataSource } @Override @@ -29,7 +29,4 @@ class JRDataSourceJDBC implements JRDataSource{ throw new JRException("Not implemented") } - - - } diff --git a/plugin/src/main/groovy/nine/jasper/JasperReportsGrailsPlugin.groovy b/plugin/src/main/groovy/nine/jasper/JasperReportsGrailsPlugin.groovy index 71f36f8..dc7a5ec 100644 --- a/plugin/src/main/groovy/nine/jasper/JasperReportsGrailsPlugin.groovy +++ b/plugin/src/main/groovy/nine/jasper/JasperReportsGrailsPlugin.groovy @@ -1,74 +1,75 @@ package nine.jasper import grails.plugins.Plugin +import groovy.util.logging.Slf4j import nine.jasper.spring.JasperView import nine.jasper.spring.JasperViewResolver +@Slf4j class JasperReportsGrailsPlugin extends Plugin { - def profiles = ['web'] - - def title = "Jasper Reports Plugin" - def description = 'Jasper Reports Plugin' - def documentation = "https://github.com/yakwroks/grails-jasper-reports" - def observe = ["controllers", 'groovyPages','viewTools'] - def loadAfter = ['controllers', 'groovyPages','viewTools'] - - - def author = "Joshua Burnett" - def authorEmail = "joshdev@9ci.com" - - def license = "APACHE" - - def pluginExcludes = [ - "grails-app/views/**/*", - "grails-app/controllers/**/*", - "grails-app/services/grails/plugin/freemarker/test/**/*", - "src/main/groovy/grails/plugin/freemarker/test/**/*", - "src/docs/**/*", - "grails-app/i18n/*", - 'grails-app/taglib/**/test/**/*', - 'scripts/**/Eclipse.groovy', - "test-plugins/**/*", - "web-app/**/*" - ] - - Closure doWithSpring() { - { -> - //def jconfig = application.mergedConfig.asMap().reporting.jasper - - println "initializing jasper reports plugin" - jasperViewResourceLocator(grails.plugin.viewtools.ViewResourceLocator) { bean -> - searchBinaryPlugins = true //whether to look in binary plugins, does not work in grails2 - - //initial searchLocations - searchPaths = []//jconfig.viewResourceLocator.searchPaths - - //resourceLoaders beans to use right after searchLocations above are scanned - //searchLoaders = [ref('tenantViewResourceLoader')] - - // in dev mode there will be a groovyPageResourceLoader with base dir set to the running project - //if(Environment.isDevelopmentEnvironmentAvailable()) <- better for Grails 3 - if (!application.warDeployed) { // <- grails2 - grailsViewPaths = ["/grails-app/views"] - webInfPrefix = "" - } - - } - - jasperViewResolver(JasperViewResolver) { - viewResourceLoader = ref("jasperViewResourceLocator") - dataSource = ref("dataSource") - reportDataKey = "data" - viewNames = ["*.jasper", "*.jrxml"] as String[] - viewClass = JasperView.class - order = 10 - //don't cache in dev mode - if (!application.warDeployed) { // <- grails2 - cache = false - } - } - - } - } -} \ No newline at end of file + def profiles = ['web'] + + def title = "Jasper Reports Plugin" + def description = 'Jasper Reports Plugin' + def documentation = "https://github.com/yakwroks/grails-jasper-reports" + def observe = ["controllers", 'groovyPages', 'viewTools'] + def loadAfter = ['controllers', 'groovyPages', 'viewTools'] + + def author = "Joshua Burnett" + def authorEmail = "joshdev@9ci.com" + + def license = "APACHE" + + def pluginExcludes = [ + "grails-app/views/**/*", + "grails-app/controllers/**/*", + "grails-app/services/grails/plugin/freemarker/test/**/*", + "src/main/groovy/grails/plugin/freemarker/test/**/*", + "src/docs/**/*", + "grails-app/i18n/*", + 'grails-app/taglib/**/test/**/*', + 'scripts/**/Eclipse.groovy', + "test-plugins/**/*", + "web-app/**/*" + ] + + Closure doWithSpring() { + { -> + //def jconfig = application.mergedConfig.asMap().reporting.jasper + + log.info "initializing jasper reports plugin" + jasperViewResourceLocator(grails.plugin.viewtools.ViewResourceLocator) { bean -> + searchBinaryPlugins = true //whether to look in binary plugins, does not work in grails2 + + //initial searchLocations + searchPaths = []//jconfig.viewResourceLocator.searchPaths + + //resourceLoaders beans to use right after searchLocations above are scanned + //searchLoaders = [ref('tenantViewResourceLoader')] + + // in dev mode there will be a groovyPageResourceLoader with base dir set to the running project + //if(Environment.isDevelopmentEnvironmentAvailable()) <- better for Grails 3 + if (!application.warDeployed) { // <- grails2 + grailsViewPaths = ["/grails-app/views"] + webInfPrefix = "" + } + + } + + jasperViewResolver(JasperViewResolver) { + viewResourceLoader = ref("jasperViewResourceLocator") + dataSource = ref("dataSource") + reportDataKey = "data" + viewNames = ["*.jasper", "*.jrxml"] as String[] + viewClass = JasperView + order = 10 + //don't cache in dev mode + if (!application.warDeployed) { // <- grails2 + cache = false + } + } + + } + } +} diff --git a/plugin/src/main/groovy/nine/jasper/JasperUtils.groovy b/plugin/src/main/groovy/nine/jasper/JasperUtils.groovy index e401b60..c0a27cd 100644 --- a/plugin/src/main/groovy/nine/jasper/JasperUtils.groovy +++ b/plugin/src/main/groovy/nine/jasper/JasperUtils.groovy @@ -35,6 +35,7 @@ import java.sql.SQLException */ @Slf4j @CompileStatic +@SuppressWarnings(['JdbcConnectionReference']) class JasperUtils { /** @@ -55,62 +56,60 @@ class JasperUtils { switch (format) { case ReportFormat.PDF: - exporter = createExporterPDF(print,output) + exporter = createExporterPDF(print, output) break case ReportFormat.XLSX: - exporter = createExporterXLSX(print,output) + exporter = createExporterXLSX(print, output) break case ReportFormat.HTML: - exporter = createExporterHTML(print,output) + exporter = createExporterHTML(print, output) break default: - throw new IllegalArgumentException("Export format [$format] not yet supported"); + throw new IllegalArgumentException("Export format [$format] not yet supported") } //standard for all - exporter.setExporterInput(new SimpleExporterInput(print)); + exporter.setExporterInput(new SimpleExporterInput(print)) return exporter } + @CompileDynamic - public static JRPdfExporter createExporterPDF(JasperPrint print,Object stream) throws JRException { - JRPdfExporter exporter = new JRPdfExporter(); - exporter.setExporterInput(new SimpleExporterInput(print)); - exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(stream)); + public static JRPdfExporter createExporterPDF(JasperPrint print, Object stream) throws JRException { + JRPdfExporter exporter = new JRPdfExporter() + exporter.setExporterInput(new SimpleExporterInput(print)) + exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(stream)) return exporter } @CompileDynamic - public static JRXlsxExporter createExporterXLSX(JasperPrint print,Object stream) throws JRException { - JRXlsxExporter exporter = new JRXlsxExporter(); - exporter.setExporterInput(new SimpleExporterInput(print)); - exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(stream)); - - print.setProperty("net.sf.jasperreports.export.xls.detect.cell.type", "true"); - print.setProperty("net.sf.jasperreports.export.xls.force.page.breaks", "true"); - //print.setProperty("net.sf.jasperreports.export.ignore.page.margins", "true"); + public static JRXlsxExporter createExporterXLSX(JasperPrint print, Object stream) throws JRException { + JRXlsxExporter exporter = new JRXlsxExporter() + exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(stream)) + + print.setProperty("net.sf.jasperreports.export.xls.detect.cell.type", "true") + print.setProperty("net.sf.jasperreports.export.xls.force.page.breaks", "true") + //print.setProperty("net.sf.jasperreports.export.ignore.page.margins", "true") return exporter } @CompileDynamic public static HtmlExporter createExporterHTML(JasperPrint print, Object writer) throws JRException { - HtmlExporter exporter = new HtmlExporter(); - exporter.setExporterInput(new SimpleExporterInput(print)); - exporter.setExporterOutput(new SimpleHtmlExporterOutput(writer)); - SimpleHtmlExporterConfiguration exporterConfig = new SimpleHtmlExporterConfiguration(); - exporterConfig.setBetweenPagesHtml(""); - exporter.setConfiguration(exporterConfig); -// SimpleHtmlReportConfiguration reportConfig = new SimpleHtmlReportConfiguration(); -// reportConfig.setRemoveEmptySpaceBetweenRows(true); -// exporter.setConfiguration(reportConfig); - - print.setProperty("net.sf.jasperreports.export.ignore.page.margins", "true"); + HtmlExporter exporter = new HtmlExporter() + exporter.setExporterInput(new SimpleExporterInput(print)) + exporter.setExporterOutput(new SimpleHtmlExporterOutput(writer)) + SimpleHtmlExporterConfiguration exporterConfig = new SimpleHtmlExporterConfiguration() + exporterConfig.setBetweenPagesHtml("") + exporter.setConfiguration(exporterConfig) +// SimpleHtmlReportConfiguration reportConfig = new SimpleHtmlReportConfiguration() +// reportConfig.setRemoveEmptySpaceBetweenRows(true) +// exporter.setConfiguration(reportConfig) + + print.setProperty("net.sf.jasperreports.export.ignore.page.margins", "true") return exporter } - - /** * Convert the given report data value to a {@code JRDataSource}. *

In the default implementation, a {@code JRDataSource}, @@ -127,14 +126,11 @@ class JasperUtils { public static JRDataSource convertReportData(Object value) throws IllegalArgumentException { if (value instanceof JRDataSource) { return value as JRDataSource - } - else if (value instanceof Collection) { + } else if (value instanceof Collection) { return new JRBeanCollectionDataSource((Collection) value) - } - else if (value instanceof Object[]) { - return new JRBeanArrayDataSource(value); - } - else { + } else if (value instanceof Object[]) { + return new JRBeanArrayDataSource(value) + } else { throw new IllegalArgumentException("Value [" + value + "] cannot be converted to a JRDataSource") } } @@ -153,14 +149,13 @@ class JasperUtils { public static void renderAsHtml(JasperReport report, Map parameters, Object reportData, Writer writer) throws JRException { - JasperPrint print = JasperFillManager.fillReport(report, parameters, convertReportData(reportData)); + JasperPrint print = JasperFillManager.fillReport(report, parameters, convertReportData(reportData)) - HtmlExporter exporter = createExporterHTML( print, writer) - exporter.exportReport(); + HtmlExporter exporter = createExporterHTML(print, writer) + exporter.exportReport() } - /** * Render a report in PDF format using the supplied report data. * Writes the results to the supplied {@code OutputStream} @@ -174,8 +169,8 @@ class JasperUtils { public static void renderAsPdf(JasperReport report, Map parameters, Object reportData, OutputStream stream) throws JRException { - JasperPrint print = JasperFillManager.fillReport(report, parameters, convertReportData(reportData)); - JasperExportManager.exportReportToPdfStream(print,stream) + JasperPrint print = JasperFillManager.fillReport(report, parameters, convertReportData(reportData)) + JasperExportManager.exportReportToPdfStream(print, stream) } /** @@ -191,12 +186,12 @@ class JasperUtils { FileSystemResource fsr Exporter exporter - if(output == null) { + if (output == null) { File tmp = File.createTempFile("jasper-${print.name}", format.extension) fsr = new FileSystemResource(tmp) - exporter = createExporter(format,print,fsr.outputStream) - }else{ - exporter = createExporter(format,print,output) + exporter = createExporter(format, print, fsr.outputStream) + } else { + exporter = createExporter(format, print, output) } exporter.exportReport() @@ -215,7 +210,7 @@ class JasperUtils { * @throws JRException */ public static Resource render(ReportFormat format, String sourceFileName, String destFileName, - Map parameters, Object reportData) throws JRException { + Map parameters, Object reportData) throws JRException { JasperReport rpt = loadReport(sourceFileName) @@ -223,7 +218,7 @@ class JasperUtils { def fsr = new FileSystemResource(destFileName) - Exporter exporter = createExporter(format,print,fsr.outputStream) + Exporter exporter = createExporter(format, print, fsr.outputStream) exporter.exportReport() return fsr @@ -246,16 +241,15 @@ class JasperUtils { JasperPrint print = JasperFillManager.fillReport(rpt, parameters, convertReportData(reportData)) - File tmp = File.createTempFile("jasper-${rpt.name}",format.extension) + File tmp = File.createTempFile("jasper-${rpt.name}", format.extension) def fsr = new FileSystemResource(tmp) - Exporter exporter = createExporter(format,print,fsr.outputStream) + Exporter exporter = createExporter(format, print, fsr.outputStream) exporter.exportReport() return fsr } - /** * just calls loadReport after converting string to a Resource */ @@ -271,18 +265,17 @@ class JasperUtils { */ public static JasperReport loadReport(Resource resource) { try { - String filename = resource.getFilename(); + String filename = resource.getFilename() if (filename != null) { if (filename.endsWith(".jasper")) { // Load pre-compiled report. - log.debug("Loading pre-compiled Jasper Report from $resource"); + log.debug("Loading pre-compiled Jasper Report from $resource") return resource.getInputStream().withStream { return (JasperReport) JRLoader.loadObject(it) } - } - else if (filename.endsWith(".jrxml")) { + } else if (filename.endsWith(".jrxml")) { // Compile report on-the-fly. - log.debug("Compiling Jasper Report loaded from $resource"); + log.debug("Compiling Jasper Report loaded from $resource") return resource.getInputStream().withStream { return JasperCompileManager.compileReport(it) } @@ -291,16 +284,16 @@ class JasperUtils { throw new IllegalArgumentException("Report filename [" + filename + "] must end in either .jasper or .jrxml") } throw new IllegalArgumentException( - "Report [$resource} getFilename can't be null"); + "Report [$resource} getFilename can't be null") } catch (IOException ex) { throw new ApplicationContextException( - "Could not load JasperReports report from " + resource, ex); + "Could not load JasperReports report from " + resource, ex) } catch (JRException ex) { throw new ApplicationContextException( - "Could not parse JasperReports report from " + resource, ex); + "Could not parse JasperReports report from " + resource, ex) } } @@ -312,18 +305,18 @@ class JasperUtils { * @return Map with keys [name, description, value( default value), type (the valueClass)] */ @CompileStatic(TypeCheckingMode.SKIP) - public static List> getPromptingParams(JasperReport jasperReport) { + public static List> getPromptingParams(JasperReport jasperReport) { JRParameter[] params = jasperReport.getParameters() return params.findAll { param -> !param.systemDefined && param.forPrompting }.collect { param -> [ - name: param.name, - description: param.description ?: StringUtils.capitalize(param.name), - value: param.defaultValueExpression?.text, - type: param.valueClass, - valueClass: param.valueClass, - valueClassName: param.valueClassName + name : param.name, + description : param.description ?: StringUtils.capitalize(param.name), + value : param.defaultValueExpression?.text, + type : param.valueClass, + valueClass : param.valueClass, + valueClassName: param.valueClassName ] } } @@ -336,31 +329,30 @@ class JasperUtils { * @param reportDataKey the dataKey to use to find the datasource * @return the JRDataSource instance to use */ - public static JRDataSource extractJasperDataSrouce(Map model, String reportDataKey = null) throws Exception { + public + static JRDataSource extractJasperDataSrouce(Map model, String reportDataKey = null) throws Exception { // Determine main report. - JRDataSource jrDataSource = null; + JRDataSource jrDataSource = null // Try with the specified key if (reportDataKey && model[reportDataKey]) { - Object reportDataValue = model.get(reportDataKey); + Object reportDataValue = model.get(reportDataKey) if (reportDataValue instanceof DataSource) { - return new JRDataSourceJDBC((DataSource)reportDataValue) - } - else { - return convertReportData(reportDataValue); + return new JRDataSourceJDBC((DataSource) reportDataValue) + } else { + return convertReportData(reportDataValue) } } //find the first item in map thats a collection - Collection values = model.values(); - jrDataSource = CollectionUtils.findValueOfType(values, JRDataSource.class); - if(jrDataSource) { + Collection values = model.values() + jrDataSource = CollectionUtils.findValueOfType(values, JRDataSource) + if (jrDataSource) { return jrDataSource - } - else{ + } else { // see if the map has a DataSource in it and grab it - def ds = CollectionUtils.findValueOfType(values, DataSource.class); + def ds = CollectionUtils.findValueOfType(values, DataSource) if (ds) { return new JRDataSourceJDBC(ds) } @@ -368,22 +360,23 @@ class JasperUtils { } - public static JasperPrint fillReport(JasperReport report, Map model, DataSource dataSource) throws DataAccessException { + public + static JasperPrint fillReport(JasperReport report, Map model, DataSource dataSource) throws DataAccessException { - Connection con = DataSourceUtils.getConnection(dataSource); + Connection con = DataSourceUtils.getConnection(dataSource) try { - return JasperFillManager.fillReport(report, model, con); + return JasperFillManager.fillReport(report, model, con) } catch (SQLException ex) { // Release Connection early, to avoid potential connection pool deadlock // in the case when the exception translator hasn't been initialized yet. - DataSourceUtils.releaseConnection(con, dataSource); - con = null; - throw new DataRetrievalFailureException(ex.message,ex) + DataSourceUtils.releaseConnection(con, dataSource) + con = null + throw new DataRetrievalFailureException(ex.message, ex) } finally { - DataSourceUtils.releaseConnection(con, dataSource); + DataSourceUtils.releaseConnection(con, dataSource) } } } diff --git a/plugin/src/main/groovy/nine/jasper/dynamic/StyleStatics.groovy b/plugin/src/main/groovy/nine/jasper/dynamic/StyleStatics.groovy index 484f9a1..70deb41 100644 --- a/plugin/src/main/groovy/nine/jasper/dynamic/StyleStatics.groovy +++ b/plugin/src/main/groovy/nine/jasper/dynamic/StyleStatics.groovy @@ -1,275 +1,276 @@ -/** - * DynamicReports - Free Java reporting library for creating reports dynamically - * - * Copyright (C) 2010 - 2016 Ricardo Mariaca - * http://www.dynamicreports.org - * - * This file is part of DynamicReports. - * - * DynamicReports is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * DynamicReports is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with DynamicReports. If not, see . - */ - -package nine.jasper.dynamic - -import groovy.transform.CompileStatic; -import net.sf.dynamicreports.report.base.expression.AbstractValueFormatter; -import net.sf.dynamicreports.report.builder.HyperLinkBuilder; -import net.sf.dynamicreports.report.builder.ReportTemplateBuilder; -import net.sf.dynamicreports.report.builder.component.ComponentBuilder; -import net.sf.dynamicreports.report.builder.datatype.BigDecimalType; -import net.sf.dynamicreports.report.builder.style.PenBuilder; -import net.sf.dynamicreports.report.builder.style.SimpleStyleBuilder; -import net.sf.dynamicreports.report.builder.style.StyleBuilder -import net.sf.dynamicreports.report.builder.style.Styles; -import net.sf.dynamicreports.report.builder.tableofcontents.TableOfContentsCustomizerBuilder -import net.sf.dynamicreports.report.constant.Evaluation -import net.sf.dynamicreports.report.constant.HorizontalAlignment; -import net.sf.dynamicreports.report.constant.HorizontalTextAlignment; -import net.sf.dynamicreports.report.constant.VerticalTextAlignment; -import net.sf.dynamicreports.report.definition.ReportParameters; - -import java.awt.* - -import static net.sf.dynamicreports.report.builder.DynamicReports.*; - -/** - * A bunch of helpers, mostly for examples and tests. should be using TemplateStyles so its configurable - */ -@CompileStatic -public class StyleStatics { - public static StyleBuilder rootStyle; - public static StyleBuilder boldStyle; - public static StyleBuilder italicStyle; - public static StyleBuilder boldCentered; - public static StyleBuilder bold12Centered; - public static StyleBuilder bold18Centered; - public static StyleBuilder bold22Centered; - - public static StyleBuilder columnStyle; - public static StyleBuilder columnTitleStyle; - public static StyleBuilder columnStyleWithGridLines; - public static StyleBuilder columnsBoolean - - public static StyleBuilder groupStyle; - public static StyleBuilder groupFooterStyle; - public static StyleBuilder groupHeaderStyle; - public static StyleBuilder groupStyleL2; - public static StyleBuilder groupStyleL3; - public static StyleBuilder groupFooterStyleL2; - public static StyleBuilder groupHeaderStyleL2; - public static StyleBuilder groupFooterStyleL3; - public static StyleBuilder groupHeaderStyleL3; - public static StyleBuilder subtotalStyle; - - public static PenBuilder lineStyle; - - public static ReportTemplateBuilder reportTemplate; - public static CurrencyType currencyType; - public static ComponentBuilder dynamicReportsComponent; - public static ComponentBuilder footerComponent; - - public static PenBuilder lineStyleLight; - public static SimpleStyleBuilder oddRowStyle; - - static init() { - rootStyle = stl.style().setName("style_root").setFont(stl.fontArial()) //(stl.font("Verdana",false,false,10)) //(stl.fontArial()); - boldStyle = stl.style(rootStyle).setName("style_bold").bold().setForegroundColor(Color.decode("#333333")); - italicStyle = stl.style(rootStyle).setName("style_italic").italic(); - boldCentered = stl.style(boldStyle).setName("style_boldCentered") - .setTextAlignment(HorizontalTextAlignment.CENTER, VerticalTextAlignment.MIDDLE); - bold12Centered = stl.style(boldCentered).setName("style_bold12Centered").setFontSize(12); - bold18Centered = stl.style(boldCentered).setName("style_bold18Centered").setFontSize(18); - bold22Centered = stl.style(boldCentered).setName("style_bold22Centered").setFontSize(22); - - lineStyle = stl.penThin().setLineColor(Color.decode("#bbbbbb")); - lineStyleLight = stl.penThin().setLineColor(Color.decode("#dddddd")); - - def lightBackground = - columnStyle = stl.style(rootStyle).setName("style_column").setPadding(3).setLeftPadding(5).setRightPadding(5) - .setVerticalTextAlignment(VerticalTextAlignment.MIDDLE); - - columnStyleWithGridLines = stl.style(columnStyle).setName("style_columnWithGridLines") - .setBottomBorder(lineStyleLight).setTopBorder(lineStyleLight); - - columnTitleStyle = stl.style(boldStyle).setName("style_columnTitle").setPadding(5) - .setHorizontalTextAlignment(HorizontalTextAlignment.CENTER) - .setBorder(lineStyle) - .setBackgroundColor(Color.decode("#f9fafb")) - .setForegroundColor(Color.decode("#4d545a")); - - columnsBoolean = Styles.style(bold18Centered).setName("style_columnBoolean").setForegroundColor(Color.decode("#3e8c41")) - //this is one the columns - subtotalStyle = stl.style(boldStyle).setName("style_subtotalDefault").setPadding(3).setLeftPadding(5).setRightPadding(5) - .setTopBorder(lineStyleLight) - .setFontSize(10); - - /** Group Styles **/ - groupStyle = stl.style(boldStyle).setName("style_group").setForegroundColor(Color.decode("#2e4e6f")) - .setHorizontalTextAlignment(HorizontalTextAlignment.LEFT) - .setFontSize(13).setTopPadding(5).setBottomPadding(5); - - //header and footer pertain to the bands - groupHeaderStyle = stl.style(groupStyle).setName("style_groupHeader")//.setBackgroundColor(Color.decode("#eeeeee")) - //.setBottomBorder(lineStyle) - .setTopPadding(0).setBottomPadding(0); - - groupFooterStyle = stl.style(groupStyle).setName("style_groupFooter").setTopPadding(0).setBottomPadding(0); - //.setTopBorder(lineStyle); - - groupStyleL2 = stl.style(groupStyle).setName("style_groupL2") - .setForegroundColor(Color.decode("#2e4e6f")) - .setTopPadding(0).setBottomPadding(0) - .setFontSize(12); - - groupHeaderStyleL2 = stl.style(groupStyle).setName("style_groupHeaderL2")//.setBackgroundColor(Color.decode("#eeeeee")) - .setBottomBorder(lineStyleLight) - .setTopPadding(5).setBottomPadding(3); - - groupFooterStyleL2 = stl.style(groupFooterStyle).setName("style_groupFooterL2"); - //.setTopBorder(lineStyle); - - groupStyleL3 = stl.style(groupStyle).setName("style_groupL3").setForegroundColor(Color.decode("#333333")) - .setTopPadding(0).setBottomPadding(0) - .setFontSize(10); - - groupHeaderStyleL3 = stl.style(groupStyle).setName("style_groupHeaderL3").setTopPadding(0).setBottomPadding(0);; - //.setBackgroundColor(Color.decode("#eeeeee")) - //.setBottomBorder(lineStyle) - //.setTopPadding(3).setBottomPadding(3); - - groupFooterStyleL3 = stl.style(groupFooterStyleL2).setName("style_groupFooterL3"); - //.setTopBorder(lineStyle); - - StyleBuilder crosstabGroupStyle = stl.style(columnTitleStyle); - StyleBuilder crosstabGroupTotalStyle = stl.style(columnTitleStyle) - .setBackgroundColor(new Color(170, 170, 170)); - StyleBuilder crosstabGrandTotalStyle = stl.style(columnTitleStyle) - .setBackgroundColor(new Color(140, 140, 140)); - StyleBuilder crosstabCellStyle = stl.style(columnStyle) - .setBorder(stl.pen1Point()); - - TableOfContentsCustomizerBuilder tableOfContentsCustomizer = tableOfContentsCustomizer() - .setHeadingStyle(0, stl.style(rootStyle).bold()); - - def rowstyle = stl.style().setName("style_oddRowStyle").setBackgroundColor(Color.decode("#f9fafb")) - .setBottomBorder(stl.penThin().setLineColor(Color.decode("#dddddd"))) - .setTopBorder(stl.penThin().setLineColor(Color.decode("#dddddd"))); - - oddRowStyle = stl.simpleStyle().setBackgroundColor(Color.decode("#f9fafb")) - .setBottomBorder(stl.penThin().setLineColor(Color.decode("#dddddd"))) - .setTopBorder(stl.penThin().setLineColor(Color.decode("#dddddd"))); - - reportTemplate = template() - //.setLanguage(Language.GROOVY) - .setLocale(Locale.ENGLISH) - .setColumnStyle(Styles.templateStyle("columng")) - .setColumnTitleStyle(Styles.templateStyle("columnTitle")) - .setGroupStyle(groupStyle) - //.setGroupFooterStyle(groupFooterStyleL2) - .setGroupTitleStyle(groupStyle) - .setSubtotalStyle(subtotalStyle) - //.highlightDetailOddRows().setDetailOddRowStyle(oddRowStyle) - .crosstabHighlightEvenRows() - .setCrosstabGroupStyle(crosstabGroupStyle) - .setCrosstabGroupTotalStyle(crosstabGroupTotalStyle) - .setCrosstabGrandTotalStyle(crosstabGrandTotalStyle) - .setCrosstabCellStyle(crosstabCellStyle) - .setTableOfContentsCustomizer(tableOfContentsCustomizer); - - currencyType = new CurrencyType(); - - HyperLinkBuilder link = hyperLink(exp.jasperSyntaxText("http://www.dynamicreports.org")); - dynamicReportsComponent = - cmp.horizontalList( - cmp.image( new URL("http://9ci.github.io/www/assets/images/9ci-logo-orange.png")).setFixedDimension(60, 60), - cmp.verticalList( - cmp.text(exp.jasperSyntaxText("DynamicReports Examples")) - .setStyle(bold22Centered) - .setHorizontalTextAlignment(HorizontalTextAlignment.LEFT), - cmp.text(exp.jasperSyntaxText("http://www.dynamicreports.org")) - .setStyle(italicStyle).setHyperLink(link) - ) - ).setFixedWidth(300); - - footerComponent = cmp.pageXofY() - .setStyle( - stl.style(boldCentered) - .setTopBorder(stl.pen1Point())); - } - - - /** - * Creates custom component which is possible to add to any report band component - */ - public static ComponentBuilder createTitleComponent(String label) { - return cmp.horizontalList() - .add( - dynamicReportsComponent, - cmp.text(exp.jasperSyntaxText(label)) - .setStyle(bold18Centered) - .setHorizontalTextAlignment(HorizontalTextAlignment.RIGHT) - ) - .newRow() - .add(cmp.line()) - .newRow() - .add(cmp.verticalGap(3)); - } - - public static ComponentBuilder createFooter() { - def pgOf = cmp.text(exp.jasperSyntax(' "Page "+$V{PAGE_NUMBER}+" of" ')) - .setHorizontalAlignment(HorizontalAlignment.RIGHT) - - def pgTotal = cmp.text(exp.jasperSyntax(' " " + $V{PAGE_NUMBER}')) - .setEvaluationTime(Evaluation.REPORT) - .setHorizontalAlignment(HorizontalAlignment.LEFT) - .setWidth(10) - - //def page = cmp.horizontalList().add(pgOf,pgTotal) - def date = cmp.text(exp.jasperSyntax('new java.util.Date()')).setPattern('EEEEE dd MMMMM yyyy') - - return cmp.horizontalList() - .add(cmp.verticalGap(3)) - .newRow() - .add(date,pgOf,pgTotal) - - } - - public static CurrencyValueFormatter createCurrencyValueFormatter(String label) { - return new CurrencyValueFormatter(label); - } - - public static class CurrencyType extends BigDecimalType { - private static final long serialVersionUID = 1L; - - @Override - public String getPattern() { - return "\$ #,###.00"; - } - } - - private static class CurrencyValueFormatter extends AbstractValueFormatter { - private static final long serialVersionUID = 1L; - - private String label; - - public CurrencyValueFormatter(String label) { - this.label = label; - } - - @Override - public String format(Number value, ReportParameters reportParameters) { - return label + currencyType.valueToString(value, reportParameters.getLocale()); - } - } -} \ No newline at end of file +/** + * DynamicReports - Free Java reporting library for creating reports dynamically + * + * Copyright (C) 2010 - 2016 Ricardo Mariaca + * http://www.dynamicreports.org + * + * This file is part of DynamicReports. + * + * DynamicReports is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DynamicReports is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with DynamicReports. If not, see . + */ +package nine.jasper.dynamic + +import groovy.transform.CompileStatic +import net.sf.dynamicreports.report.base.expression.AbstractValueFormatter +import net.sf.dynamicreports.report.builder.HyperLinkBuilder +import net.sf.dynamicreports.report.builder.ReportTemplateBuilder +import net.sf.dynamicreports.report.builder.component.ComponentBuilder +import net.sf.dynamicreports.report.builder.datatype.BigDecimalType +import net.sf.dynamicreports.report.builder.style.PenBuilder +import net.sf.dynamicreports.report.builder.style.SimpleStyleBuilder +import net.sf.dynamicreports.report.builder.style.StyleBuilder +import net.sf.dynamicreports.report.builder.style.Styles +import net.sf.dynamicreports.report.builder.tableofcontents.TableOfContentsCustomizerBuilder +import net.sf.dynamicreports.report.constant.Evaluation +import net.sf.dynamicreports.report.constant.HorizontalAlignment +import net.sf.dynamicreports.report.constant.HorizontalTextAlignment +import net.sf.dynamicreports.report.constant.VerticalTextAlignment +import net.sf.dynamicreports.report.definition.ReportParameters + +import java.awt.* + +import static net.sf.dynamicreports.report.builder.DynamicReports.* + +/** + * A bunch of helpers, mostly for examples and tests. should be using TemplateStyles so its configurable + */ +@CompileStatic +public class StyleStatics { + public static StyleBuilder rootStyle + public static StyleBuilder boldStyle + public static StyleBuilder italicStyle + public static StyleBuilder boldCentered + public static StyleBuilder bold12Centered + public static StyleBuilder bold18Centered + public static StyleBuilder bold22Centered + + public static StyleBuilder columnStyle + public static StyleBuilder columnTitleStyle + public static StyleBuilder columnStyleWithGridLines + public static StyleBuilder columnsBoolean + + public static StyleBuilder groupStyle + public static StyleBuilder groupFooterStyle + public static StyleBuilder groupHeaderStyle + public static StyleBuilder groupStyleL2 + public static StyleBuilder groupStyleL3 + public static StyleBuilder groupFooterStyleL2 + public static StyleBuilder groupHeaderStyleL2 + public static StyleBuilder groupFooterStyleL3 + public static StyleBuilder groupHeaderStyleL3 + public static StyleBuilder subtotalStyle + + public static PenBuilder lineStyle + + public static ReportTemplateBuilder reportTemplate + public static CurrencyType currencyType + public static ComponentBuilder dynamicReportsComponent + public static ComponentBuilder footerComponent + + public static PenBuilder lineStyleLight + public static SimpleStyleBuilder oddRowStyle + + static init() { + rootStyle = stl.style().setName("style_root").setFont(stl.fontArial()) + //(stl.font("Verdana",false,false,10)) //(stl.fontArial()) + boldStyle = stl.style(rootStyle).setName("style_bold").bold().setForegroundColor(Color.decode("#333333")) + italicStyle = stl.style(rootStyle).setName("style_italic").italic() + boldCentered = stl.style(boldStyle).setName("style_boldCentered") + .setTextAlignment(HorizontalTextAlignment.CENTER, VerticalTextAlignment.MIDDLE) + bold12Centered = stl.style(boldCentered).setName("style_bold12Centered").setFontSize(12) + bold18Centered = stl.style(boldCentered).setName("style_bold18Centered").setFontSize(18) + bold22Centered = stl.style(boldCentered).setName("style_bold22Centered").setFontSize(22) + + lineStyle = stl.penThin().setLineColor(Color.decode("#bbbbbb")) + lineStyleLight = stl.penThin().setLineColor(Color.decode("#dddddd")) + + def lightBackground = + columnStyle = stl.style(rootStyle).setName("style_column").setPadding(3).setLeftPadding(5).setRightPadding(5) + .setVerticalTextAlignment(VerticalTextAlignment.MIDDLE) + + columnStyleWithGridLines = stl.style(columnStyle).setName("style_columnWithGridLines") + .setBottomBorder(lineStyleLight).setTopBorder(lineStyleLight) + + columnTitleStyle = stl.style(boldStyle).setName("style_columnTitle").setPadding(5) + .setHorizontalTextAlignment(HorizontalTextAlignment.CENTER) + .setBorder(lineStyle) + .setBackgroundColor(Color.decode("#f9fafb")) + .setForegroundColor(Color.decode("#4d545a")) + + columnsBoolean = Styles.style(bold18Centered).setName("style_columnBoolean").setForegroundColor(Color.decode("#3e8c41")) + //this is one the columns + subtotalStyle = stl.style(boldStyle).setName("style_subtotalDefault").setPadding(3).setLeftPadding(5).setRightPadding(5) + .setTopBorder(lineStyleLight) + .setFontSize(10) + + /** Group Styles **/ + groupStyle = stl.style(boldStyle).setName("style_group").setForegroundColor(Color.decode("#2e4e6f")) + .setHorizontalTextAlignment(HorizontalTextAlignment.LEFT) + .setFontSize(13).setTopPadding(5).setBottomPadding(5) + + //header and footer pertain to the bands + groupHeaderStyle = stl.style(groupStyle).setName("style_groupHeader")//.setBackgroundColor(Color.decode("#eeeeee")) + //.setBottomBorder(lineStyle) + .setTopPadding(0).setBottomPadding(0) + + groupFooterStyle = stl.style(groupStyle).setName("style_groupFooter").setTopPadding(0).setBottomPadding(0) + //.setTopBorder(lineStyle) + + groupStyleL2 = stl.style(groupStyle).setName("style_groupL2") + .setForegroundColor(Color.decode("#2e4e6f")) + .setTopPadding(0).setBottomPadding(0) + .setFontSize(12) + + groupHeaderStyleL2 = stl.style(groupStyle).setName("style_groupHeaderL2")//.setBackgroundColor(Color.decode("#eeeeee")) + .setBottomBorder(lineStyleLight) + .setTopPadding(5).setBottomPadding(3) + + groupFooterStyleL2 = stl.style(groupFooterStyle).setName("style_groupFooterL2") + //.setTopBorder(lineStyle) + + groupStyleL3 = stl.style(groupStyle).setName("style_groupL3").setForegroundColor(Color.decode("#333333")) + .setTopPadding(0).setBottomPadding(0) + .setFontSize(10) + + groupHeaderStyleL3 = stl.style(groupStyle).setName("style_groupHeaderL3").setTopPadding(0).setBottomPadding(0) + //.setBackgroundColor(Color.decode("#eeeeee")) + //.setBottomBorder(lineStyle) + //.setTopPadding(3).setBottomPadding(3) + + groupFooterStyleL3 = stl.style(groupFooterStyleL2).setName("style_groupFooterL3") + //.setTopBorder(lineStyle) + + StyleBuilder crosstabGroupStyle = stl.style(columnTitleStyle) + StyleBuilder crosstabGroupTotalStyle = stl.style(columnTitleStyle) + .setBackgroundColor(new Color(170, 170, 170)) + StyleBuilder crosstabGrandTotalStyle = stl.style(columnTitleStyle) + .setBackgroundColor(new Color(140, 140, 140)) + StyleBuilder crosstabCellStyle = stl.style(columnStyle) + .setBorder(stl.pen1Point()) + + TableOfContentsCustomizerBuilder tableOfContentsCustomizer = tableOfContentsCustomizer() + .setHeadingStyle(0, stl.style(rootStyle).bold()) + + def rowstyle = stl.style().setName("style_oddRowStyle").setBackgroundColor(Color.decode("#f9fafb")) + .setBottomBorder(stl.penThin().setLineColor(Color.decode("#dddddd"))) + .setTopBorder(stl.penThin().setLineColor(Color.decode("#dddddd"))) + + oddRowStyle = stl.simpleStyle().setBackgroundColor(Color.decode("#f9fafb")) + .setBottomBorder(stl.penThin().setLineColor(Color.decode("#dddddd"))) + .setTopBorder(stl.penThin().setLineColor(Color.decode("#dddddd"))) + + reportTemplate = template() + //.setLanguage(Language.GROOVY) + .setLocale(Locale.ENGLISH) + .setColumnStyle(Styles.templateStyle("columng")) + .setColumnTitleStyle(Styles.templateStyle("columnTitle")) + .setGroupStyle(groupStyle) + //.setGroupFooterStyle(groupFooterStyleL2) + .setGroupTitleStyle(groupStyle) + .setSubtotalStyle(subtotalStyle) + //.highlightDetailOddRows().setDetailOddRowStyle(oddRowStyle) + .crosstabHighlightEvenRows() + .setCrosstabGroupStyle(crosstabGroupStyle) + .setCrosstabGroupTotalStyle(crosstabGroupTotalStyle) + .setCrosstabGrandTotalStyle(crosstabGrandTotalStyle) + .setCrosstabCellStyle(crosstabCellStyle) + .setTableOfContentsCustomizer(tableOfContentsCustomizer) + + currencyType = new CurrencyType() + + HyperLinkBuilder link = hyperLink(exp.jasperSyntaxText("http://www.dynamicreports.org")) + dynamicReportsComponent = + cmp.horizontalList( + cmp.image(new URL("http://9ci.github.io/www/assets/images/9ci-logo-orange.png")).setFixedDimension(60, 60), + cmp.verticalList( + cmp.text(exp.jasperSyntaxText("DynamicReports Examples")) + .setStyle(bold22Centered) + .setHorizontalTextAlignment(HorizontalTextAlignment.LEFT), + cmp.text(exp.jasperSyntaxText("http://www.dynamicreports.org")) + .setStyle(italicStyle).setHyperLink(link) + ) + ).setFixedWidth(300) + + footerComponent = cmp.pageXofY() + .setStyle( + stl.style(boldCentered) + .setTopBorder(stl.pen1Point())) + } + + /** + * Creates custom component which is possible to add to any report band component + */ + public static ComponentBuilder createTitleComponent(String label) { + return cmp.horizontalList() + .add( + dynamicReportsComponent, + cmp.text(exp.jasperSyntaxText(label)) + .setStyle(bold18Centered) + .setHorizontalTextAlignment(HorizontalTextAlignment.RIGHT) + ) + .newRow() + .add(cmp.line()) + .newRow() + .add(cmp.verticalGap(3)) + } + + public static ComponentBuilder createFooter() { + def pgOf = cmp.text(exp.jasperSyntax(' "Page "+$V{PAGE_NUMBER}+" of" ')) + .setHorizontalAlignment(HorizontalAlignment.RIGHT) + + def pgTotal = cmp.text(exp.jasperSyntax(' " " + $V{PAGE_NUMBER}')) + .setEvaluationTime(Evaluation.REPORT) + .setHorizontalAlignment(HorizontalAlignment.LEFT) + .setWidth(10) + + //def page = cmp.horizontalList().add(pgOf,pgTotal) + def date = cmp.text(exp.jasperSyntax('new java.util.Date()')).setPattern('EEEEE dd MMMMM yyyy') + + return cmp.horizontalList() + .add(cmp.verticalGap(3)) + .newRow() + .add(date, pgOf, pgTotal) + + } + + public static CurrencyValueFormatter createCurrencyValueFormatter(String label) { + return new CurrencyValueFormatter(label) + } + + @CompileStatic + public static class CurrencyType extends BigDecimalType { + private static final long serialVersionUID = 1L + + @Override + public String getPattern() { + return "\$ #,###.00" + } + } + + @CompileStatic + private static class CurrencyValueFormatter extends AbstractValueFormatter { + private static final long serialVersionUID = 1L + + private String label + + public CurrencyValueFormatter(String label) { + this.label = label + } + + @Override + public String format(Number value, ReportParameters reportParameters) { + return label + currencyType.valueToString(value, reportParameters.getLocale()) + } + } +} diff --git a/plugin/src/main/groovy/nine/jasper/dynamic/TemplateStyles.groovy b/plugin/src/main/groovy/nine/jasper/dynamic/TemplateStyles.groovy index 3b94ded..c26c4ff 100644 --- a/plugin/src/main/groovy/nine/jasper/dynamic/TemplateStyles.groovy +++ b/plugin/src/main/groovy/nine/jasper/dynamic/TemplateStyles.groovy @@ -1,194 +1,187 @@ -/** - * DynamicReports - Free Java reporting library for creating reports dynamically - * - * Copyright (C) 2010 - 2016 Ricardo Mariaca - * http://www.dynamicreports.org - * - * This file is part of DynamicReports. - * - * DynamicReports is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * DynamicReports is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with DynamicReports. If not, see . - */ - -package nine.jasper.dynamic - -import groovy.transform.CompileStatic -import net.sf.dynamicreports.report.base.expression.AbstractValueFormatter -import net.sf.dynamicreports.report.builder.DynamicReports -import net.sf.dynamicreports.report.builder.HyperLinkBuilder -import net.sf.dynamicreports.report.builder.ReportTemplateBuilder -import net.sf.dynamicreports.report.builder.component.ComponentBuilder -import net.sf.dynamicreports.report.builder.datatype.BigDecimalType -import net.sf.dynamicreports.report.builder.style.PenBuilder -import net.sf.dynamicreports.report.builder.style.ReportStyleBuilder -import net.sf.dynamicreports.report.builder.style.SimpleStyleBuilder -import net.sf.dynamicreports.report.builder.style.StyleBuilder -import net.sf.dynamicreports.report.builder.style.Styles -import net.sf.dynamicreports.report.builder.style.TemplateStylesBuilder -import net.sf.dynamicreports.report.builder.tableofcontents.TableOfContentsCustomizerBuilder -import net.sf.dynamicreports.report.constant.Evaluation -import net.sf.dynamicreports.report.constant.HorizontalAlignment -import net.sf.dynamicreports.report.constant.HorizontalTextAlignment -import net.sf.dynamicreports.report.constant.VerticalTextAlignment -import net.sf.dynamicreports.report.definition.ReportParameters -import org.springframework.context.ApplicationContext -import org.springframework.core.io.ResourceLoader - -import java.awt.* - -import static net.sf.dynamicreports.report.builder.DynamicReports.* - -/** - * A bunch of helpers, mostly for examples and tests. should be using TemplateStyles so its configurable - */ -@CompileStatic -public class TemplateStyles { - public static ReportStyleBuilder root = Styles.templateStyle("root") - public static ReportStyleBuilder bold = Styles.templateStyle("bold") - public static ReportStyleBuilder italic = Styles.templateStyle("italic") - public static ReportStyleBuilder boldCentered = Styles.templateStyle("boldCentered") - public static ReportStyleBuilder bold12Centered = Styles.templateStyle("bold12Centered") - public static ReportStyleBuilder bold18Centered = Styles.templateStyle("bold18Centered") - public static ReportStyleBuilder bold22Centered = Styles.templateStyle("bold22Centered") - - public static ReportStyleBuilder column = Styles.templateStyle("column") - public static ReportStyleBuilder columnTitle = Styles.templateStyle("columnTitle") - public static ReportStyleBuilder columnWithGridLines = Styles.templateStyle("columnWithGridLines") - public static ReportStyleBuilder columnsBoolean = Styles.templateStyle("columnsBoolean") - - public static ReportStyleBuilder group = Styles.templateStyle("group") - public static ReportStyleBuilder groupTitle = Styles.templateStyle("groupTitle") - public static ReportStyleBuilder groupFooter = Styles.templateStyle("groupFooter") - public static ReportStyleBuilder groupHeader = Styles.templateStyle("groupHeader") - public static ReportStyleBuilder groupL2 = Styles.templateStyle("groupL2") - public static ReportStyleBuilder groupL3 = Styles.templateStyle("groupL3") - public static ReportStyleBuilder groupFooterL2 = Styles.templateStyle("groupFooterL2") - public static ReportStyleBuilder groupHeaderL2 = Styles.templateStyle("groupHeaderL2") - public static ReportStyleBuilder groupFooterL3 = Styles.templateStyle("groupFooterL3") - public static ReportStyleBuilder groupHeaderL3 = Styles.templateStyle("groupHeaderL3") - public static ReportStyleBuilder subtotal = Styles.templateStyle("subtotal") - - - public static PenBuilder lineStyle = stl.penThin().setLineColor(Color.decode("#bbbbbb")); - public static PenBuilder lineStyleLight = stl.penThin().setLineColor(Color.decode("#dddddd"));; - - public static ReportTemplateBuilder reportTemplate; - public static CurrencyType currencyType = new CurrencyType() - public static ComponentBuilder dynamicReportsComponent; - public static ComponentBuilder footerComponent; - - public static SimpleStyleBuilder oddRowStyle = stl.simpleStyle().setBackgroundColor(Color.decode("#f9fafb")) - .setBottomBorder(stl.penThin().setLineColor(Color.decode("#dddddd"))) - .setTopBorder(stl.penThin().setLineColor(Color.decode("#dddddd"))) - - public static ReportTemplateBuilder getReportTemplate(){ - DynamicReports.template() - //.setLanguage(Language.GROOVY) - .setLocale(Locale.ENGLISH) - .setColumnStyle(column) - .setColumnTitleStyle(columnTitle) - .setGroupStyle(group) - //.setGroupFooterStyle(groupFooterStyleL2) - .setGroupTitleStyle(groupTitle) - .setSubtotalStyle(subtotal) - } - - /** - * Creates custom component which is possible to add to any report band component - */ - public static ComponentBuilder createTitleComponent(String label) { - HyperLinkBuilder link = hyperLink(exp.jasperSyntaxText("http://www.dynamicreports.org")) - def dynamicReportsComponent = - cmp.horizontalList( - cmp.image( new URL("http://9ci.github.io/www/assets/images/9ci-logo-orange.png")).setFixedDimension(60, 60), - cmp.verticalList( - cmp.text(exp.jasperSyntaxText("DynamicReports Examples")) - .setStyle(bold22Centered) - .setHorizontalTextAlignment(HorizontalTextAlignment.LEFT), - cmp.text(exp.jasperSyntaxText("http://www.dynamicreports.org")) - .setStyle(italic).setHyperLink(link) - ) - ).setFixedWidth(300); - - return cmp.horizontalList() - .add( - dynamicReportsComponent, - cmp.text(exp.jasperSyntaxText(label)) - .setStyle(bold18Centered) - .setHorizontalTextAlignment(HorizontalTextAlignment.RIGHT) - ) - .newRow() - .add(cmp.line()) - .newRow() - .add(cmp.verticalGap(3)); - } - - public static ComponentBuilder createFooter() { - def pgOf = cmp.text(exp.jasperSyntax(' "Page "+$V{PAGE_NUMBER}+" of" ')) - .setHorizontalAlignment(HorizontalAlignment.RIGHT) - - def pgTotal = cmp.text(exp.jasperSyntax(' " " + $V{PAGE_NUMBER}')) - .setEvaluationTime(Evaluation.REPORT) - .setHorizontalAlignment(HorizontalAlignment.LEFT) - .setWidth(10) - - //def page = cmp.horizontalList().add(pgOf,pgTotal) - def date = cmp.text(exp.jasperSyntax('new java.util.Date()')).setPattern('EEEEE dd MMMMM yyyy') - - return cmp.horizontalList() - .add(cmp.verticalGap(3)) - .newRow() - .add(date,pgOf,pgTotal) - - } - - //TODO finish so a custom jrtx can be passed into this - static TemplateStylesBuilder loadStyles(ResourceLoader loader, String jrtxFileName = null) { - if(!jrtxFileName) jrtxFileName = "nine/jasper/TemplateStyles.jrtx" - - def resTemplateStyles = loader.getResource("classpath:$jrtxFileName") - assert resTemplateStyles.exists() - return Styles.loadStyles(resTemplateStyles.inputStream) - } - - - public static CurrencyValueFormatter createCurrencyValueFormatter(String label) { - return new CurrencyValueFormatter(label); - } - - - - public static class CurrencyType extends BigDecimalType { - private static final long serialVersionUID = 1L; - - @Override - public String getPattern() { - return "\$ #,###.00"; - } - } - - private static class CurrencyValueFormatter extends AbstractValueFormatter { - private static final long serialVersionUID = 1L; - - private String label; - - public CurrencyValueFormatter(String label) { - this.label = label; - } - - @Override - public String format(Number value, ReportParameters reportParameters) { - return label + currencyType.valueToString(value, reportParameters.getLocale()); - } - } -} \ No newline at end of file +/** + * DynamicReports - Free Java reporting library for creating reports dynamically + * + * Copyright (C) 2010 - 2016 Ricardo Mariaca + * http://www.dynamicreports.org + * + * This file is part of DynamicReports. + * + * DynamicReports is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DynamicReports is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with DynamicReports. If not, see . + */ +package nine.jasper.dynamic + +import groovy.transform.CompileStatic +import net.sf.dynamicreports.report.base.expression.AbstractValueFormatter +import net.sf.dynamicreports.report.builder.DynamicReports +import net.sf.dynamicreports.report.builder.HyperLinkBuilder +import net.sf.dynamicreports.report.builder.ReportTemplateBuilder +import net.sf.dynamicreports.report.builder.component.ComponentBuilder +import net.sf.dynamicreports.report.builder.datatype.BigDecimalType +import net.sf.dynamicreports.report.builder.style.PenBuilder +import net.sf.dynamicreports.report.builder.style.ReportStyleBuilder +import net.sf.dynamicreports.report.builder.style.SimpleStyleBuilder +import net.sf.dynamicreports.report.builder.style.Styles +import net.sf.dynamicreports.report.builder.style.TemplateStylesBuilder +import net.sf.dynamicreports.report.constant.Evaluation +import net.sf.dynamicreports.report.constant.HorizontalAlignment +import net.sf.dynamicreports.report.constant.HorizontalTextAlignment +import net.sf.dynamicreports.report.definition.ReportParameters +import org.springframework.core.io.ResourceLoader + +import java.awt.* + +import static net.sf.dynamicreports.report.builder.DynamicReports.* + +/** + * A bunch of helpers, mostly for examples and tests. should be using TemplateStyles so its configurable + */ +@CompileStatic +public class TemplateStyles { + public static ReportStyleBuilder root = Styles.templateStyle("root") + public static ReportStyleBuilder bold = Styles.templateStyle("bold") + public static ReportStyleBuilder italic = Styles.templateStyle("italic") + public static ReportStyleBuilder boldCentered = Styles.templateStyle("boldCentered") + public static ReportStyleBuilder bold12Centered = Styles.templateStyle("bold12Centered") + public static ReportStyleBuilder bold18Centered = Styles.templateStyle("bold18Centered") + public static ReportStyleBuilder bold22Centered = Styles.templateStyle("bold22Centered") + + public static ReportStyleBuilder column = Styles.templateStyle("column") + public static ReportStyleBuilder columnTitle = Styles.templateStyle("columnTitle") + public static ReportStyleBuilder columnWithGridLines = Styles.templateStyle("columnWithGridLines") + public static ReportStyleBuilder columnsBoolean = Styles.templateStyle("columnsBoolean") + + public static ReportStyleBuilder group = Styles.templateStyle("group") + public static ReportStyleBuilder groupTitle = Styles.templateStyle("groupTitle") + public static ReportStyleBuilder groupFooter = Styles.templateStyle("groupFooter") + public static ReportStyleBuilder groupHeader = Styles.templateStyle("groupHeader") + public static ReportStyleBuilder groupL2 = Styles.templateStyle("groupL2") + public static ReportStyleBuilder groupL3 = Styles.templateStyle("groupL3") + public static ReportStyleBuilder groupFooterL2 = Styles.templateStyle("groupFooterL2") + public static ReportStyleBuilder groupHeaderL2 = Styles.templateStyle("groupHeaderL2") + public static ReportStyleBuilder groupFooterL3 = Styles.templateStyle("groupFooterL3") + public static ReportStyleBuilder groupHeaderL3 = Styles.templateStyle("groupHeaderL3") + public static ReportStyleBuilder subtotal = Styles.templateStyle("subtotal") + + public static PenBuilder lineStyle = stl.penThin().setLineColor(Color.decode("#bbbbbb")) + public static PenBuilder lineStyleLight = stl.penThin().setLineColor(Color.decode("#dddddd")) + + public static ReportTemplateBuilder reportTemplate + public static CurrencyType currencyType = new CurrencyType() + public static ComponentBuilder dynamicReportsComponent + public static ComponentBuilder footerComponent + + public static SimpleStyleBuilder oddRowStyle = stl.simpleStyle().setBackgroundColor(Color.decode("#f9fafb")) + .setBottomBorder(stl.penThin().setLineColor(Color.decode("#dddddd"))) + .setTopBorder(stl.penThin().setLineColor(Color.decode("#dddddd"))) + + public static ReportTemplateBuilder getReportTemplate() { + DynamicReports.template() + //.setLanguage(Language.GROOVY) + .setLocale(Locale.ENGLISH) + .setColumnStyle(column) + .setColumnTitleStyle(columnTitle) + .setGroupStyle(group) + //.setGroupFooterStyle(groupFooterStyleL2) + .setGroupTitleStyle(groupTitle) + .setSubtotalStyle(subtotal) + } + + /** + * Creates custom component which is possible to add to any report band component + */ + public static ComponentBuilder createTitleComponent(String label) { + HyperLinkBuilder link = hyperLink(exp.jasperSyntaxText("http://www.dynamicreports.org")) + def dynamicReportsComponent = + cmp.horizontalList( + cmp.image(new URL("http://9ci.github.io/www/assets/images/9ci-logo-orange.png")).setFixedDimension(60, 60), + cmp.verticalList( + cmp.text(exp.jasperSyntaxText("DynamicReports Examples")) + .setStyle(bold22Centered) + .setHorizontalTextAlignment(HorizontalTextAlignment.LEFT), + cmp.text(exp.jasperSyntaxText("http://www.dynamicreports.org")) + .setStyle(italic).setHyperLink(link) + ) + ).setFixedWidth(300) + + return cmp.horizontalList() + .add( + dynamicReportsComponent, + cmp.text(exp.jasperSyntaxText(label)) + .setStyle(bold18Centered) + .setHorizontalTextAlignment(HorizontalTextAlignment.RIGHT) + ) + .newRow() + .add(cmp.line()) + .newRow() + .add(cmp.verticalGap(3)) + } + + public static ComponentBuilder createFooter() { + def pgOf = cmp.text(exp.jasperSyntax(' "Page "+$V{PAGE_NUMBER}+" of" ')) + .setHorizontalAlignment(HorizontalAlignment.RIGHT) + + def pgTotal = cmp.text(exp.jasperSyntax(' " " + $V{PAGE_NUMBER}')) + .setEvaluationTime(Evaluation.REPORT) + .setHorizontalAlignment(HorizontalAlignment.LEFT) + .setWidth(10) + + //def page = cmp.horizontalList().add(pgOf,pgTotal) + def date = cmp.text(exp.jasperSyntax('new java.util.Date()')).setPattern('EEEEE dd MMMMM yyyy') + + return cmp.horizontalList() + .add(cmp.verticalGap(3)) + .newRow() + .add(date, pgOf, pgTotal) + + } + + //TODO finish so a custom jrtx can be passed into this + static TemplateStylesBuilder loadStyles(ResourceLoader loader, String jrtxFileName = null) { + if (!jrtxFileName) jrtxFileName = "nine/jasper/TemplateStyles.jrtx" + + def resTemplateStyles = loader.getResource("classpath:$jrtxFileName") + assert resTemplateStyles.exists() + return Styles.loadStyles(resTemplateStyles.inputStream) + } + + public static CurrencyValueFormatter createCurrencyValueFormatter(String label) { + return new CurrencyValueFormatter(label) + } + + @CompileStatic + public static class CurrencyType extends BigDecimalType { + private static final long serialVersionUID = 1L + + @Override + public String getPattern() { + return "\$ #,###.00" + } + } + + @CompileStatic + private static class CurrencyValueFormatter extends AbstractValueFormatter { + private static final long serialVersionUID = 1L + + private String label + + public CurrencyValueFormatter(String label) { + this.label = label + } + + @Override + public String format(Number value, ReportParameters reportParameters) { + return label + currencyType.valueToString(value, reportParameters.getLocale()) + } + } +} diff --git a/plugin/src/main/groovy/nine/jasper/gorm/GormJasperDataSource.groovy b/plugin/src/main/groovy/nine/jasper/gorm/GormJasperDataSource.groovy index 7a44528..b96d439 100644 --- a/plugin/src/main/groovy/nine/jasper/gorm/GormJasperDataSource.groovy +++ b/plugin/src/main/groovy/nine/jasper/gorm/GormJasperDataSource.groovy @@ -1,9 +1,9 @@ package nine.jasper.gorm -import net.sf.jasperreports.engine.JRException; +import groovy.transform.CompileDynamic +import net.sf.jasperreports.engine.JRException import net.sf.jasperreports.engine.JRField -import net.sf.jasperreports.engine.JRRewindableDataSource; - +import net.sf.jasperreports.engine.JRRewindableDataSource /** * A data source implementation that wraps a collection of JavaBean objects. @@ -18,74 +18,54 @@ import net.sf.jasperreports.engine.JRRewindableDataSource; * @author Teodor Danciu (teodord@users.sourceforge.net) */ //FIXME Finish this -public class GormJasperDataSource implements JRRewindableDataSource{ +@CompileDynamic +public class GormJasperDataSource implements JRRewindableDataSource { + private Collection data + private Iterator iterator + private Object currentBean - /** - * - */ - private Collection data; - private Iterator iterator; - private Object currentBean; - - - /** - * - */ - public GormJasperDataSource(Collection beanCollection) - { - this(beanCollection, true); + public GormJasperDataSource(Collection beanCollection) { + this(beanCollection, true) } - /** * */ - public GormJasperDataSource(Collection beanCollection, boolean isUseFieldDescription) - { - super(isUseFieldDescription); + public GormJasperDataSource(Collection beanCollection, boolean isUseFieldDescription) { + super(isUseFieldDescription) - this.data = beanCollection; + this.data = beanCollection - if (this.data != null) - { - this.iterator = this.data.iterator(); + if (this.data != null) { + this.iterator = this.data.iterator() } } - @Override - public boolean next() - { - boolean hasNext = false; + public boolean next() { + boolean hasNext = false - if (this.iterator != null) - { - hasNext = this.iterator.hasNext(); + if (this.iterator != null) { + hasNext = this.iterator.hasNext() - if (hasNext) - { - this.currentBean = this.iterator.next(); + if (hasNext) { + this.currentBean = this.iterator.next() } } - return hasNext; + return hasNext } - @Override - public Object getFieldValue(JRField field) throws JRException - { - return getFieldValue(currentBean, field); + public Object getFieldValue(JRField field) throws JRException { + return getFieldValue(currentBean, field) } - @Override - public void moveFirst() - { - if (this.data != null) - { - this.iterator = this.data.iterator(); + public void moveFirst() { + if (this.data != null) { + this.iterator = this.data.iterator() } } @@ -94,9 +74,8 @@ public class GormJasperDataSource implements JRRewindableDataSource{ * * @return the underlying bean collection */ - public Collection getData() - { - return data; + public Collection getData() { + return data } /** @@ -105,9 +84,8 @@ public class GormJasperDataSource implements JRRewindableDataSource{ * * @return the total number of records of this data source */ - public int getRecordCount() - { - return data == null ? 0 : data.size(); + public int getRecordCount() { + return data == null ? 0 : data.size() } // /** @@ -118,6 +96,6 @@ public class GormJasperDataSource implements JRRewindableDataSource{ // */ // public JRBeanCollectionDataSource cloneDataSource() // { -// return new JRBeanCollectionDataSource(data); +// return new JRBeanCollectionDataSource(data) // } } diff --git a/plugin/src/main/groovy/nine/jasper/spring/AbstractJasperReportsView.groovy b/plugin/src/main/groovy/nine/jasper/spring/AbstractJasperReportsView.groovy index 9e47016..51b8173 100644 --- a/plugin/src/main/groovy/nine/jasper/spring/AbstractJasperReportsView.groovy +++ b/plugin/src/main/groovy/nine/jasper/spring/AbstractJasperReportsView.groovy @@ -1,7 +1,7 @@ /* * Copyright 2002-2014 the original author or authors. * - * Licensed under the Apache License, Version 2.0 (the "License"); + * Licensed under the Apache License, Version 2.0 (the "License") * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package nine.jasper.spring import groovy.transform.CompileStatic @@ -91,420 +90,417 @@ import javax.sql.DataSource @CompileStatic public abstract class AbstractJasperReportsView extends AbstractUrlBasedView { - /** - * Constant that defines "Content-Disposition" header. - */ - static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition"; - - /** - * The default Content-Disposition header. Used to make IE play nice. - */ - static final String CONTENT_DISPOSITION_INLINE = "inline"; - - /** - * A String key used to lookup the {@code JRDataSource} in the model. - */ - String reportDataKey = "data" - - /** - * Stores the paths to any sub-report files used by this top-level report, - * along with the keys they are mapped to in the top-level report file. - */ - Properties subReportUrls; - - /** - * Stores the names of any data source objects that need to be converted to - * {@code JRDataSource} instances and included in the report parameters - * to be passed on to a sub-report. - */ - String[] subReportDataKeys; - - /** - * Stores the headers to written with each response - */ - Properties headers; - - /** - * Stores the {@code DataSource}, if any, used as the report data source. - */ - DataSource jdbcDataSource; - - /** - * The {@code JasperReport} that is used to render the view. - */ - JasperReport report; - - /** - * Holds mappings between sub-report keys and {@code JasperReport} objects. - */ - private Map subReports; - - - /** - * Set the name of the model attribute that represents the report data. - * If not specified, the model map will be searched for a matching value type. - *

A {@code JRDataSource} will be taken as-is. For other types, conversion - * will apply: By default, a {@code java.util.Collection} will be converted - * to {@code JRBeanCollectionDataSource}, and an object array to - * {@code JRBeanArrayDataSource}. - *

Note: If you pass in a Collection or object array in the model map - * for use as plain report parameter, rather than as report data to extract fields - * from, you need to specify the key for the actual report data to use, to avoid - * mis-detection of report data by type. - * @see net.sf.jasperreports.engine.data.JRBeanCollectionDataSource - * @see net.sf.jasperreports.engine.data.JRBeanArrayDataSource - */ - public void setReportDataKey(String reportDataKey) { - this.reportDataKey = reportDataKey; - } - - /** - * Specify resource paths which must be loaded as instances of - * {@code JasperReport} and passed to the JasperReports engine for - * rendering as sub-reports, under the same keys as in this mapping. - * @param subReports mapping between model keys and resource paths - * (Spring resource locations) - * @see #setUrl - * @see org.springframework.context.ApplicationContext#getResource - */ - public void setSubReportUrls(Properties subReports) { - this.subReportUrls = subReports; - } - - /** - * Set the list of names corresponding to the model parameters that will contain - * data source objects for use in sub-reports. Spring will convert these objects - * to instances of {@code JRDataSource} where applicable and will then - * include the resulting {@code JRDataSource} in the parameters passed into - * the JasperReports engine. - *

The name specified in the list should correspond to an attribute in the - * model Map, and to a sub-report data source parameter in your report file. - * If you pass in {@code JRDataSource} objects as model attributes, - * specifying this list of keys is not required. - *

If you specify a list of sub-report data keys, it is required to also - * specify a {@code reportDataKey} for the main report, to avoid confusion - * between the data source objects for the various reports involved. - * @param subReportDataKeys list of names for sub-report data source objects - * @see #setReportDataKey - * @see JRDataSource - * @see net.sf.jasperreports.engine.data.JRBeanCollectionDataSource - * @see net.sf.jasperreports.engine.data.JRBeanArrayDataSource - */ - public void setSubReportDataKeys(String... subReportDataKeys) { - this.subReportDataKeys = subReportDataKeys; - } - - /** - * JasperReports views do not strictly required a 'url' value. - * Alternatively, the {@link #getReport()} template method may be overridden. - */ - @Override - protected boolean isUrlRequired() { - return false; - } - - /** - * Checks to see that a valid report file URL is supplied in the - * configuration. Compiles the report file is necessary. - *

Subclasses can add custom initialization logic by overriding - * the {@link #onInit} method. - */ - @Override - protected final void initApplicationContext() throws ApplicationContextException { - this.report = loadReport(); - - // Load sub reports if required, and check data source parameters. - if (subReportUrls) { - if (this.subReportDataKeys != null && this.subReportDataKeys.length > 0 && this.reportDataKey == null) { - throw new ApplicationContextException( - "'reportDataKey' for main report is required when specifying a value for 'subReportDataKeys'"); - } - this.subReports = new HashMap(this.subReportUrls.size()); - //FIXME replace this with viewResourceLocator - for (Enumeration urls = this.subReportUrls.propertyNames(); urls.hasMoreElements();) { - String key = (String) urls.nextElement(); - String path = this.subReportUrls.getProperty(key); - Resource resource = getApplicationContext().getResource(path); - - this.subReports.put(key, JasperUtils.loadReport(resource)); - } - } - - if (this.headers == null) { - this.headers = new Properties(); - } - if (!this.headers.containsKey(HEADER_CONTENT_DISPOSITION)) { - this.headers.setProperty(HEADER_CONTENT_DISPOSITION, CONTENT_DISPOSITION_INLINE); - } - - onInit(); - } - - /** - * Subclasses can override this to add some custom initialization logic. Called - * by {@link #initApplicationContext()} as soon as all standard initialization logic - * has finished executing. - * @see #initApplicationContext() - */ - protected void onInit() { - } - - /** - * Load the main {@code JasperReport} from the specified {@code Resource}. - * If the {@code Resource} points to an uncompiled report design file then the - * report file is compiled dynamically and loaded into memory. - * @return a {@code JasperReport} instance, or {@code null} if no main - * report has been statically defined - */ - protected JasperReport loadReport() { - String url = getUrl(); - if (url == null) { - return null; - } - //FIXME replace this with the viewResourceLoader - //it should have the full aboslute URL at this point in the game - Resource mainReport = getApplicationContext().getResource(url); - return JasperUtils.loadReport(mainReport) - } - - /** - * Finds the report data to use for rendering the report and then invokes the - * {@link #renderReport} method that should be implemented by the subclass. - * @param model the model map, as passed in for view rendering. Must contain - * a report data value that can be converted to a {@code JRDataSource}, - * according to the rules of the {@link #fillReport} method. - */ - @Override - protected void renderMergedOutputModel( - Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { - - exposeSubReports(model) - - // Expose Spring-managed Locale and MessageSource. - exposeLocalizationContext(model, request); - - // Fill the report. - JasperPrint filledReport = fillReport(model); - postProcessReport(filledReport, model); - - // Prepare response and render report. - populateHeaders(response); - renderReport(filledReport, model, response); - } - - - public void exposeSubReports(Map model) { - if (this.subReports != null) { - // Expose sub-reports as model attributes. - model.putAll(this.subReports); - - // Transform any collections etc into JRDataSources for sub reports. - if (this.subReportDataKeys != null) { - for (String key : this.subReportDataKeys) { - model.put(key, convertReportData(model.get(key))); - } - } - } - } - - /** - * Expose current Spring-managed Locale and MessageSource to JasperReports i18n - * ($R expressions etc). The MessageSource should only be exposed as JasperReports - * resource bundle if no such bundle is defined in the report itself. - *

The default implementation exposes the Spring RequestContext Locale and a - * MessageSourceResourceBundle adapter for the Spring ApplicationContext, - * analogous to the {@code JstlUtils.exposeLocalizationContext} method. - * @see org.springframework.web.servlet.support.RequestContextUtils#getLocale - * @see MessageSourceResourceBundle - * @see #getApplicationContext() - * @see JRParameter#REPORT_LOCALE - * @see JRParameter#REPORT_RESOURCE_BUNDLE - * @see org.springframework.web.servlet.support.JstlUtils#exposeLocalizationContext - */ - protected void exposeLocalizationContext(Map model, HttpServletRequest request) { - RequestContext rc = new RequestContext(request, getServletContext()); - Locale locale = rc.getLocale(); - if (!model.containsKey(JRParameter.REPORT_LOCALE)) { - model.put(JRParameter.REPORT_LOCALE, locale); - } - TimeZone timeZone = rc.getTimeZone(); - if (timeZone != null && !model.containsKey(JRParameter.REPORT_TIME_ZONE)) { - model.put(JRParameter.REPORT_TIME_ZONE, timeZone); - } - JasperReport report = getReport(); - if ((report == null || report.getResourceBundle() == null) && !model.containsKey(JRParameter.REPORT_RESOURCE_BUNDLE)) { - model.put(JRParameter.REPORT_RESOURCE_BUNDLE, new MessageSourceResourceBundle(rc.getMessageSource(), locale)); - } - } - - /** - * Create a populated {@code JasperPrint} instance from the configured - * {@code JasperReport} instance. - *

By default, this method will use any {@code JRDataSource} instance - * (or wrappable {@code Object}) that can be located using {@link #setReportDataKey}, - * a lookup for type {@code JRDataSource} in the model Map, or a special value - * retrieved via {@link #getReportData}. - *

If no {@code JRDataSource} can be found, this method will use a JDBC - * {@code Connection} obtained from the configured {@code javax.sql.DataSource} - * (or a DataSource attribute in the model). If no JDBC DataSource can be found - * either, the JasperReports engine will be invoked with plain model Map, - * assuming that the model contains parameters that identify the source - * for report data (e.g. Hibernate or JPA queries). - * @param model the model for this request - * @throws IllegalArgumentException if no {@code JRDataSource} can be found - * and no {@code javax.sql.DataSource} is supplied - * @throws JRException if there is an error when populating the report using - * a {@code JRDataSource} - * @return the populated {@code JasperPrint} instance - * @see #getReportData - * @see #setJdbcDataSource - */ - protected JasperPrint fillReport(Map model) throws Exception { - // Determine main report. - JasperReport report = getReport(); - if (report == null) { - throw new IllegalStateException("No main report defined for 'fillReport' - " + - "specify a 'url' on this view or override 'getReport()' or 'fillReport(Map)'"); - } - - JRDataSource jrDataSource = JasperUtils.extractJasperDataSrouce(model,this.reportDataKey) - DataSource jdbcDataSourceToUse = null; - - - if (!jrDataSource && this.jdbcDataSource) { - jrDataSource = new JRDataSourceJDBC(jdbcDataSource) - } - - if (jrDataSource && jrDataSource instanceof JRDataSourceJDBC) { - return JasperUtils.fillReport(report,model,((JRDataSourceJDBC)jrDataSource).dataSource) - } - else { - // Determine JRDataSource for main report. - if (jrDataSource == null) { - //try grabbing it form the first collection in the model - jrDataSource = getReportData(model); - } - if (jrDataSource) { - // Use the JasperReports JRDataSource. - if (logger.isDebugEnabled()) { - logger.debug("Filling report with JRDataSource [" + jrDataSource + "]"); - } - return JasperFillManager.fillReport(report, model, jrDataSource); - } - else { - // Assume that the model contains parameters that identify - // the source for report data (e.g. Hibernate or JPA queries). - logger.debug("Filling report with plain model"); - return JasperFillManager.fillReport(report, model); - } - } - } - - /** - * Populates the headers in the {@code HttpServletResponse} with the - * headers supplied by the user. - */ - private void populateHeaders(HttpServletResponse response) { - // Apply the headers to the response. - for (Enumeration en = this.headers.propertyNames(); en.hasMoreElements();) { - String key = (String) en.nextElement(); - response.addHeader(key, this.headers.getProperty(key)); - } - } - - /** - * Determine the {@code JasperReport} to fill. - * Called by {@link #fillReport}. - *

The default implementation returns the report as statically configured - * through the 'url' property (and loaded by {@link #loadReport()}). - * Can be overridden in subclasses in order to dynamically obtain a - * {@code JasperReport} instance. As an alternative, consider - * overriding the {@link #fillReport} template method itself. - * @return an instance of {@code JasperReport} - */ - protected JasperReport getReport() { - return this.report; - } - - /** - * Create an appropriate {@code JRDataSource} for passed-in report data. - * Called by {@link #fillReport} when its own lookup steps were not successful. - *

The default implementation looks for a value of type {@code java.util.Collection} - * or object array (in that order). Can be overridden in subclasses. - * @param model the model map, as passed in for view rendering - * @return the {@code JRDataSource} or {@code null} if the data source is not found - * @see #getReportDataTypes - * @see #convertReportData - */ - protected JRDataSource getReportData(Map model) { - // Try to find matching attribute, of given prioritized types. - Object value = CollectionUtils.findValueOfType(model.values(), getReportDataTypes()); - return (value != null ? convertReportData(value) : null); - } - - /** - * Return the value types that can be converted to a {@code JRDataSource}, - * in prioritized order. Should only return types that the - * {@link #convertReportData} method is actually able to convert. - *

Default value types are: {@code java.util.Collection} and {@code Object} array. - * @return the value types in prioritized order - */ - protected Class[] getReportDataTypes() { - return [Collection.class, ([] as Object[]).class] as Class[] - } - - /** - * Convert the given report data value to a {@code JRDataSource}. - *

The default implementation delegates to {@code JasperReportUtils} unless - * the report data value is an instance of {@code JRDataSourceProvider}. - * A {@code JRDataSource}, {@code JRDataSourceProvider}, - * {@code java.util.Collection} or object array is detected. - * {@code JRDataSource}s are returned as is, whilst {@code JRDataSourceProvider}s - * are used to create an instance of {@code JRDataSource} which is then returned. - * The latter two are converted to {@code JRBeanCollectionDataSource} or - * {@code JRBeanArrayDataSource}, respectively. - * @param value the report data value to convert - * @return the JRDataSource - * @throws IllegalArgumentException if the value could not be converted - * @see JasperReportsUtils#convertReportData - * @see JRDataSource - * @see net.sf.jasperreports.engine.data.JRBeanCollectionDataSource - * @see net.sf.jasperreports.engine.data.JRBeanArrayDataSource - */ - protected JRDataSource convertReportData(Object value) throws IllegalArgumentException { - return JasperUtils.convertReportData(value); - } - - /** - * Template method to be overridden for custom post-processing of the - * populated report. Invoked after filling but before rendering. - *

The default implementation is empty. - * @param populatedReport the populated {@code JasperPrint} - * @param model the map containing report parameters - * @throws Exception if post-processing failed - */ - protected void postProcessReport(JasperPrint populatedReport, Map model) throws Exception { - } - - /** - * Subclasses should implement this method to perform the actual rendering process. - *

Note that the content type has not been set yet: Implementers should build - * a content type String and set it via {@code response.setContentType}. - * If necessary, this can include a charset clause for a specific encoding. - * The latter will only be necessary for textual output onto a Writer, and only - * in case of the encoding being specified in the JasperReports exporter parameters. - *

WARNING: Implementers should not use {@code response.setCharacterEncoding} - * unless they are willing to depend on Servlet API 2.4 or higher. Prefer a - * concatenated content type String with a charset clause instead. - * @param populatedReport the populated {@code JasperPrint} to render - * @param model the map containing report parameters - * @param response the HTTP response the report should be rendered to - * @throws Exception if rendering failed - * @see javax.servlet.ServletResponse#setContentType - * @see javax.servlet.ServletResponse#setCharacterEncoding - */ - protected abstract void renderReport( - JasperPrint populatedReport, Map model, HttpServletResponse response) - throws Exception; + /** + * Constant that defines "Content-Disposition" header. + */ + static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition" + + /** + * The default Content-Disposition header. Used to make IE play nice. + */ + static final String CONTENT_DISPOSITION_INLINE = "inline" + + /** + * A String key used to lookup the {@code JRDataSource} in the model. + */ + String reportDataKey = "data" + + /** + * Stores the paths to any sub-report files used by this top-level report, + * along with the keys they are mapped to in the top-level report file. + */ + Properties subReportUrls + + /** + * Stores the names of any data source objects that need to be converted to + * {@code JRDataSource} instances and included in the report parameters + * to be passed on to a sub-report. + */ + String[] subReportDataKeys + + /** + * Stores the headers to written with each response + */ + Properties headers + + /** + * Stores the {@code DataSource}, if any, used as the report data source. + */ + DataSource jdbcDataSource + + /** + * The {@code JasperReport} that is used to render the view. + */ + JasperReport report + + /** + * Holds mappings between sub-report keys and {@code JasperReport} objects. + */ + private Map subReports + + /** + * Set the name of the model attribute that represents the report data. + * If not specified, the model map will be searched for a matching value type. + *

A {@code JRDataSource} will be taken as-is. For other types, conversion + * will apply: By default, a {@code java.util.Collection} will be converted + * to {@code JRBeanCollectionDataSource}, and an object array to + * {@code JRBeanArrayDataSource}. + *

Note: If you pass in a Collection or object array in the model map + * for use as plain report parameter, rather than as report data to extract fields + * from, you need to specify the key for the actual report data to use, to avoid + * mis-detection of report data by type. + * @see net.sf.jasperreports.engine.data.JRBeanCollectionDataSource + * @see net.sf.jasperreports.engine.data.JRBeanArrayDataSource + */ + public void setReportDataKey(String reportDataKey) { + this.reportDataKey = reportDataKey + } + + /** + * Specify resource paths which must be loaded as instances of + * {@code JasperReport} and passed to the JasperReports engine for + * rendering as sub-reports, under the same keys as in this mapping. + * @param subReports mapping between model keys and resource paths + * (Spring resource locations) + * @see #setUrl + * @see org.springframework.context.ApplicationContext#getResource + */ + public void setSubReportUrls(Properties subReports) { + this.subReportUrls = subReports + } + + /** + * Set the list of names corresponding to the model parameters that will contain + * data source objects for use in sub-reports. Spring will convert these objects + * to instances of {@code JRDataSource} where applicable and will then + * include the resulting {@code JRDataSource} in the parameters passed into + * the JasperReports engine. + *

The name specified in the list should correspond to an attribute in the + * model Map, and to a sub-report data source parameter in your report file. + * If you pass in {@code JRDataSource} objects as model attributes, + * specifying this list of keys is not required. + *

If you specify a list of sub-report data keys, it is required to also + * specify a {@code reportDataKey} for the main report, to avoid confusion + * between the data source objects for the various reports involved. + * @param subReportDataKeys list of names for sub-report data source objects + * @see #setReportDataKey + * @see JRDataSource + * @see net.sf.jasperreports.engine.data.JRBeanCollectionDataSource + * @see net.sf.jasperreports.engine.data.JRBeanArrayDataSource + */ + public void setSubReportDataKeys(String... subReportDataKeys) { + this.subReportDataKeys = subReportDataKeys + } + + /** + * JasperReports views do not strictly required a 'url' value. + * Alternatively, the {@link #getReport()} template method may be overridden. + */ + @Override + protected boolean isUrlRequired() { + return false + } + + /** + * Checks to see that a valid report file URL is supplied in the + * configuration. Compiles the report file is necessary. + *

Subclasses can add custom initialization logic by overriding + * the {@link #onInit} method. + */ + @Override + protected final void initApplicationContext() throws ApplicationContextException { + this.report = loadReport() + + // Load sub reports if required, and check data source parameters. + if (subReportUrls) { + if (this.subReportDataKeys != null && this.subReportDataKeys.length > 0 && this.reportDataKey == null) { + throw new ApplicationContextException( + "'reportDataKey' for main report is required when specifying a value for 'subReportDataKeys'") + } + this.subReports = new HashMap(this.subReportUrls.size()) + //FIXME replace this with viewResourceLocator + for (Enumeration urls = this.subReportUrls.propertyNames() ; urls.hasMoreElements();) { + String key = (String) urls.nextElement() + String path = this.subReportUrls.getProperty(key) + Resource resource = getApplicationContext().getResource(path) + + this.subReports.put(key, JasperUtils.loadReport(resource)) + } + } + + if (this.headers == null) { + this.headers = new Properties() + } + if (!this.headers.containsKey(HEADER_CONTENT_DISPOSITION)) { + this.headers.setProperty(HEADER_CONTENT_DISPOSITION, CONTENT_DISPOSITION_INLINE) + } + + onInit() + } + + /** + * Subclasses can override this to add some custom initialization logic. Called + * by {@link #initApplicationContext()} as soon as all standard initialization logic + * has finished executing. + * @see #initApplicationContext() + */ + @SuppressWarnings(['EmptyMethodInAbstractClass']) + protected void onInit() { + } + + /** + * Load the main {@code JasperReport} from the specified {@code Resource}. + * If the {@code Resource} points to an uncompiled report design file then the + * report file is compiled dynamically and loaded into memory. + * @return a {@code JasperReport} instance, or {@code null} if no main + * report has been statically defined + */ + protected JasperReport loadReport() { + String url = getUrl() + if (url == null) { + return null + } + //FIXME replace this with the viewResourceLoader + //it should have the full aboslute URL at this point in the game + Resource mainReport = getApplicationContext().getResource(url) + return JasperUtils.loadReport(mainReport) + } + + /** + * Finds the report data to use for rendering the report and then invokes the + * {@link #renderReport} method that should be implemented by the subclass. + * @param model the model map, as passed in for view rendering. Must contain + * a report data value that can be converted to a {@code JRDataSource}, + * according to the rules of the {@link #fillReport} method. + */ + @Override + protected void renderMergedOutputModel( + Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + + exposeSubReports(model) + + // Expose Spring-managed Locale and MessageSource. + exposeLocalizationContext(model, request) + + // Fill the report. + JasperPrint filledReport = fillReport(model) + postProcessReport(filledReport, model) + + // Prepare response and render report. + populateHeaders(response) + renderReport(filledReport, model, response) + } + + public void exposeSubReports(Map model) { + if (this.subReports != null) { + // Expose sub-reports as model attributes. + model.putAll(this.subReports) + + // Transform any collections etc into JRDataSources for sub reports. + if (this.subReportDataKeys != null) { + for (String key : this.subReportDataKeys) { + model.put(key, convertReportData(model.get(key))) + } + } + } + } + + /** + * Expose current Spring-managed Locale and MessageSource to JasperReports i18n + * ($R expressions etc). The MessageSource should only be exposed as JasperReports + * resource bundle if no such bundle is defined in the report itself. + *

The default implementation exposes the Spring RequestContext Locale and a + * MessageSourceResourceBundle adapter for the Spring ApplicationContext, + * analogous to the {@code JstlUtils.exposeLocalizationContext} method. + * @see org.springframework.web.servlet.support.RequestContextUtils#getLocale + * @see MessageSourceResourceBundle + * @see #getApplicationContext() + * @see JRParameter#REPORT_LOCALE + * @see JRParameter#REPORT_RESOURCE_BUNDLE + * @see org.springframework.web.servlet.support.JstlUtils#exposeLocalizationContext + */ + protected void exposeLocalizationContext(Map model, HttpServletRequest request) { + RequestContext rc = new RequestContext(request, getServletContext()) + Locale locale = rc.getLocale() + if (!model.containsKey(JRParameter.REPORT_LOCALE)) { + model.put(JRParameter.REPORT_LOCALE, locale) + } + TimeZone timeZone = rc.getTimeZone() + if (timeZone != null && !model.containsKey(JRParameter.REPORT_TIME_ZONE)) { + model.put(JRParameter.REPORT_TIME_ZONE, timeZone) + } + JasperReport report = getReport() + if ((report == null || report.getResourceBundle() == null) && !model.containsKey(JRParameter.REPORT_RESOURCE_BUNDLE)) { + model.put(JRParameter.REPORT_RESOURCE_BUNDLE, new MessageSourceResourceBundle(rc.getMessageSource(), locale)) + } + } + + /** + * Create a populated {@code JasperPrint} instance from the configured + * {@code JasperReport} instance. + *

By default, this method will use any {@code JRDataSource} instance + * (or wrappable {@code Object}) that can be located using {@link #setReportDataKey}, + * a lookup for type {@code JRDataSource} in the model Map, or a special value + * retrieved via {@link #getReportData}. + *

If no {@code JRDataSource} can be found, this method will use a JDBC + * {@code Connection} obtained from the configured {@code javax.sql.DataSource} + * (or a DataSource attribute in the model). If no JDBC DataSource can be found + * either, the JasperReports engine will be invoked with plain model Map, + * assuming that the model contains parameters that identify the source + * for report data (e.g. Hibernate or JPA queries). + * @param model the model for this request + * @throws IllegalArgumentException if no {@code JRDataSource} can be found + * and no {@code javax.sql.DataSource} is supplied + * @throws JRException if there is an error when populating the report using + * a {@code JRDataSource} + * @return the populated {@code JasperPrint} instance + * @see #getReportData + * @see #setJdbcDataSource + */ + protected JasperPrint fillReport(Map model) throws Exception { + // Determine main report. + JasperReport report = getReport() + if (report == null) { + throw new IllegalStateException("No main report defined for 'fillReport' - " + + "specify a 'url' on this view or override 'getReport()' or 'fillReport(Map)'") + } + + JRDataSource jrDataSource = JasperUtils.extractJasperDataSrouce(model, this.reportDataKey) + DataSource jdbcDataSourceToUse = null + + if (!jrDataSource && this.jdbcDataSource) { + jrDataSource = new JRDataSourceJDBC(jdbcDataSource) + } + + if (jrDataSource && jrDataSource instanceof JRDataSourceJDBC) { + return JasperUtils.fillReport(report, model, ((JRDataSourceJDBC) jrDataSource).dataSource) + } else { + // Determine JRDataSource for main report. + if (jrDataSource == null) { + //try grabbing it form the first collection in the model + jrDataSource = getReportData(model) + } + if (jrDataSource) { + // Use the JasperReports JRDataSource. + if (logger.isDebugEnabled()) { + logger.debug("Filling report with JRDataSource [" + jrDataSource + "]") + } + return JasperFillManager.fillReport(report, model, jrDataSource) + } else { + // Assume that the model contains parameters that identify + // the source for report data (e.g. Hibernate or JPA queries). + logger.debug("Filling report with plain model") + return JasperFillManager.fillReport(report, model) + } + } + } + + /** + * Populates the headers in the {@code HttpServletResponse} with the + * headers supplied by the user. + */ + private void populateHeaders(HttpServletResponse response) { + // Apply the headers to the response. + for (Enumeration en = this.headers.propertyNames() ; en.hasMoreElements();) { + String key = (String) en.nextElement() + response.addHeader(key, this.headers.getProperty(key)) + } + } + + /** + * Determine the {@code JasperReport} to fill. + * Called by {@link #fillReport}. + *

The default implementation returns the report as statically configured + * through the 'url' property (and loaded by {@link #loadReport()}). + * Can be overridden in subclasses in order to dynamically obtain a + * {@code JasperReport} instance. As an alternative, consider + * overriding the {@link #fillReport} template method itself. + * @return an instance of {@code JasperReport} + */ + protected JasperReport getReport() { + return this.report + } + + /** + * Create an appropriate {@code JRDataSource} for passed-in report data. + * Called by {@link #fillReport} when its own lookup steps were not successful. + *

The default implementation looks for a value of type {@code java.util.Collection} + * or object array (in that order). Can be overridden in subclasses. + * @param model the model map, as passed in for view rendering + * @return the {@code JRDataSource} or {@code null} if the data source is not found + * @see #getReportDataTypes + * @see #convertReportData + */ + protected JRDataSource getReportData(Map model) { + // Try to find matching attribute, of given prioritized types. + Object value = CollectionUtils.findValueOfType(model.values(), getReportDataTypes()) + return (value != null ? convertReportData(value) : null) + } + + /** + * Return the value types that can be converted to a {@code JRDataSource}, + * in prioritized order. Should only return types that the + * {@link #convertReportData} method is actually able to convert. + *

Default value types are: {@code java.util.Collection} and {@code Object} array. + * @return the value types in prioritized order + */ + protected Class[] getReportDataTypes() { + return [Collection.class, ([] as Object[]).class] as Class[] + } + + /** + * Convert the given report data value to a {@code JRDataSource}. + *

The default implementation delegates to {@code JasperReportUtils} unless + * the report data value is an instance of {@code JRDataSourceProvider}. + * A {@code JRDataSource}, {@code JRDataSourceProvider}, + * {@code java.util.Collection} or object array is detected. + * {@code JRDataSource}s are returned as is, whilst {@code JRDataSourceProvider}s + * are used to create an instance of {@code JRDataSource} which is then returned. + * The latter two are converted to {@code JRBeanCollectionDataSource} or + * {@code JRBeanArrayDataSource}, respectively. + * @param value the report data value to convert + * @return the JRDataSource + * @throws IllegalArgumentException if the value could not be converted + * @see JasperReportsUtils#convertReportData + * @see JRDataSource + * @see net.sf.jasperreports.engine.data.JRBeanCollectionDataSource + * @see net.sf.jasperreports.engine.data.JRBeanArrayDataSource + */ + protected JRDataSource convertReportData(Object value) throws IllegalArgumentException { + return JasperUtils.convertReportData(value) + } + + /** + * Template method to be overridden for custom post-processing of the + * populated report. Invoked after filling but before rendering. + *

The default implementation is empty. + * @param populatedReport the populated {@code JasperPrint} + * @param model the map containing report parameters + * @throws Exception if post-processing failed + */ + @SuppressWarnings(['EmptyMethodInAbstractClass']) + protected void postProcessReport(JasperPrint populatedReport, Map model) throws Exception { + } + + /** + * Subclasses should implement this method to perform the actual rendering process. + *

Note that the content type has not been set yet: Implementers should build + * a content type String and set it via {@code response.setContentType}. + * If necessary, this can include a charset clause for a specific encoding. + * The latter will only be necessary for textual output onto a Writer, and only + * in case of the encoding being specified in the JasperReports exporter parameters. + *

WARNING: Implementers should not use {@code response.setCharacterEncoding} + * unless they are willing to depend on Servlet API 2.4 or higher. Prefer a + * concatenated content type String with a charset clause instead. + * @param populatedReport the populated {@code JasperPrint} to render + * @param model the map containing report parameters + * @param response the HTTP response the report should be rendered to + * @throws Exception if rendering failed + * @see javax.servlet.ServletResponse#setContentType + * @see javax.servlet.ServletResponse#setCharacterEncoding + */ + protected abstract void renderReport( + JasperPrint populatedReport, Map model, HttpServletResponse response) + throws Exception } diff --git a/plugin/src/main/groovy/nine/jasper/spring/JasperReportDef.groovy b/plugin/src/main/groovy/nine/jasper/spring/JasperReportDef.groovy index b0def27..8ae3eff 100644 --- a/plugin/src/main/groovy/nine/jasper/spring/JasperReportDef.groovy +++ b/plugin/src/main/groovy/nine/jasper/spring/JasperReportDef.groovy @@ -1,57 +1,53 @@ package nine.jasper.spring -import grails.util.Holders +import groovy.transform.CompileStatic import nine.reports.ReportFormat /** * An abstract representation of a Jasper report. */ +@CompileStatic class JasperReportDef implements Serializable { - /** - * The name of the report file - * The file can be in jrxml- or jasper-format. - */ - String name - - /** - * The data source used to fill the report. - *

- * This is a list of java beans. - */ - Collection reportData - - /** - * The target file format. - */ - ReportFormat fileFormat = ReportFormat.PDF - - /** - * The generated report as OutputStream. - */ - ByteArrayOutputStream contentStream - - /** - * Additional parameters. - */ - Map parameters = [:] - - /** - * Locale setting. - */ - Locale locale - - - private getApplicationContext() { - return Holders.grailsApplication.mainContext - } - - /** - * Add a parameter to the parameter map. - * @param key , the key - * @param value , the value - */ - void addParameter(key, value) { - parameters.put(key, value) - } + /** + * The name of the report file + * The file can be in jrxml- or jasper-format. + */ + String name + + /** + * The data source used to fill the report. + *

+ * This is a list of java beans. + */ + Collection reportData + + /** + * The target file format. + */ + ReportFormat fileFormat = ReportFormat.PDF + + /** + * The generated report as OutputStream. + */ + ByteArrayOutputStream contentStream + + /** + * Additional parameters. + */ + Map parameters = [:] + + /** + * Locale setting. + */ + Locale locale + + /** + * Add a parameter to the parameter map. + * @param key , the key + * @param value , the value + */ + void addParameter(Object key, Object value) { + parameters.put(key, value) + } } diff --git a/plugin/src/main/groovy/nine/jasper/spring/JasperView.groovy b/plugin/src/main/groovy/nine/jasper/spring/JasperView.groovy index 79167ad..d754ccd 100644 --- a/plugin/src/main/groovy/nine/jasper/spring/JasperView.groovy +++ b/plugin/src/main/groovy/nine/jasper/spring/JasperView.groovy @@ -1,7 +1,7 @@ /* * Copyright 2002-2015 the original author or authors. * - * Licensed under the Apache License, Version 2.0 (the "License"); + * Licensed under the Apache License, Version 2.0 (the "License") * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * @@ -21,7 +21,7 @@ import groovy.transform.TypeCheckingMode import groovy.util.logging.Slf4j import net.sf.jasperreports.engine.JRParameter import nine.reports.ReportFormat -import net.sf.jasperreports.engine.JRAbstractExporter; +import net.sf.jasperreports.engine.JRAbstractExporter import net.sf.jasperreports.engine.JasperPrint import net.sf.jasperreports.export.Exporter import net.sf.jasperreports.export.WriterExporterOutput @@ -29,10 +29,8 @@ import nine.jasper.JasperUtils import org.springframework.web.util.WebUtils import javax.servlet.ServletOutputStream -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - - +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse /** * JasperReports view class that allows for the actual rendering format * to be specified at runtime using a parameter contained in the model. @@ -41,241 +39,231 @@ import javax.servlet.http.HttpServletResponse; @CompileStatic public class JasperView extends AbstractJasperReportsView { - /** - * The key of the model parameter that holds the format key. - */ - String formatKey = "format" - - /** - * the passed in report format from formatKey in model - */ - //ReportFormat format - - /** - * Stores the mappings of mapping keys to Content-Disposition header values. - */ - Properties contentDispositionMappings - - - /** - * Creates a new {@code JasperReportsMultiFormatView} instance - * with a default set of mappings. - */ - public JasperView() { - } - - @Override - public String getContentType() { - throw new MissingFieldException("Use model and ReportFormat, contentType no longer valid ","contentType",this.class) - } - - /** - * Set the mappings of {@code Content-Disposition} header values to - * mapping keys. If specified, Spring will look at these mappings to determine - * the value of the {@code Content-Disposition} header for a given - * format mapping. - */ - public void setContentDispositionMappings(Properties mappings) { - this.contentDispositionMappings = mappings; - } - - /** - * Return the mappings of {@code Content-Disposition} header values to - * mapping keys. Mainly available for configuration through property paths - * that specify individual keys. - */ - public Properties getContentDispositionMappings() { - if (this.contentDispositionMappings == null) { - this.contentDispositionMappings = new Properties(); - } - return this.contentDispositionMappings; - } - - /** - * renders outside of a request Web environment - * @param model - * @param output the writer or stream you want to render to. - * @return null if output was passed , or the temp file if output was null - */ - public void render(ReportFormat format, Map params, Collection data, Object output){ - params << [data:data,format:format] - render(params,output) - } - - /** - * renders outside of a request Web environment - * @param model - * @param output the writer or stream you want to render to. - * @return null if output was passed , or the temp file if output was null - */ - public void render(Map model, Object output){ - setupFormat(model) - //TODO should we still in case stuff was set that we want passed through? - //Map mergedModel = createMergedOutputModel(model, request, response); - //prepareResponse(request, response); - - // TODO how to get subReports - //exposeSubReports(model) - // Expose Spring-managed Locale and MessageSource. - //TODO how to get localization into the report - //exposeLocalizationContext(model, request); - - JasperPrint print = fillReport(model) - JasperUtils.render(model.format as ReportFormat, print, output ) - } - - /** - * This is the main method that Grails/Spring calls to render the view in the MVC context - * @param model - * @param request - * @param response - * @throws Exception - */ - @Override - public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { - setupFormat(model,response) - - super.render(model,request,response) - /** - the super is in AbstractView and calls - Map mergedModel = createMergedOutputModel(model, request, response); - prepareResponse(request, response); - renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); - ^ is in AbstractJasperReportsView and calls - exposeSubReports(model) - exposeLocalizationContext(model, request); - JasperPrint filledReport = fillReport(model); - postProcessReport(filledReport, model); - populateHeaders(response); - renderReport(filledReport, model, response); - - */ - } - - @CompileStatic(TypeCheckingMode.SKIP) - public void setupFormat(Map model,HttpServletResponse response = null){ - - //if the model has one then use that as the override - if(model[formatKey]) { - def fmat = model[formatKey] - model[formatKey] = fmat instanceof ReportFormat ? fmat : ReportFormat.get(fmat) - } - - if(response && !model[formatKey]){ - //use the one that grails puts in the response - model[formatKey] = ReportFormat.get(response.format) - } - //if format is null still then just use html - model[formatKey] = model[formatKey] ?: ReportFormat.HTML - - if(model[formatKey] == ReportFormat.HTML - && !model.containsKey(JRParameter.IS_IGNORE_PAGINATION)){ - model.put(JRParameter.IS_IGNORE_PAGINATION, true) - } - } - - /** - * Locates the format key in the model using the configured discriminator key and uses this - * key to lookup the appropriate view class from the mappings. The rendering of the - * report is then delegated to an instance of that view class. - */ - @Override - @CompileStatic(TypeCheckingMode.SKIP) - protected void renderReport(JasperPrint populatedReport, Map model, HttpServletResponse response) - throws Exception { - - log.debug("Rendering report using format mapping key [$model.format]"); - //contentType = format.mimeType - - populateContentDispositionIfNecessary(response, model[formatKey].extension); - - if (model[formatKey].downloadContent) { - renderReportUsingOutputStream(populatedReport, response, model.format); - } - else { - renderReportUsingWriter(populatedReport, response, model.format); - } - - } - - /** - * Adds/overwrites the {@code Content-Disposition} header value with the format-specific - * value if the mappings have been specified and a valid one exists for the given format. - * @param response the {@code HttpServletResponse} to set the header in - * @param format the format key of the mapping - * @see #setContentDispositionMappings - */ - private void populateContentDispositionIfNecessary(HttpServletResponse response, String format) { - if (this.contentDispositionMappings != null) { - String header = this.contentDispositionMappings.getProperty(format); - if (header != null) { - if (logger.isDebugEnabled()) { - logger.debug("Setting Content-Disposition header to: [" + header + "]"); - } - response.setHeader(AbstractJasperReportsView.HEADER_CONTENT_DISPOSITION, header); - } - } - } - - /** - * We need to write text to the response Writer. - * @param print the populated {@code JasperPrint} to render - * @param response the HTTP response the report should be rendered to - * @throws Exception if rendering failed - */ - @CompileStatic(TypeCheckingMode.SKIP) - protected void renderReportUsingWriter(JasperPrint print, HttpServletResponse response, ReportFormat format) throws Exception { - - JRAbstractExporter exporter = (JRAbstractExporter)createExporter(format, print, response.getWriter()) - // Copy the encoding configured for the report into the response. - String contentType = format.mimeType - String encoding = (exporter.exporterOutput as WriterExporterOutput).getEncoding() - if (encoding) { - // Only apply encoding if content type is specified but does not contain charset clause already. - if (contentType != null && !contentType.toLowerCase().contains(WebUtils.CONTENT_TYPE_CHARSET_PREFIX)) { - contentType = contentType + WebUtils.CONTENT_TYPE_CHARSET_PREFIX + encoding; - } - } - response.setContentType(contentType); - - exporter.exportReport() - } - - /** - * We need to write binary output to the response OutputStream. - * @param exporter the JasperReports exporter to use - * @param populatedReport the populated {@code JasperPrint} to render - * @param response the HTTP response the report should be rendered to - * @throws Exception if rendering failed - */ - protected void renderReportUsingOutputStream(JasperPrint print, HttpServletResponse response, ReportFormat format) throws Exception { - response.setContentType(format.mimeType); - - //workaround for an IE bug when sending download content via HTTPS. - //Copied from AbstractView.prepareResponse - response.setHeader("Pragma", "private") - response.setHeader("Cache-Control", "private, must-revalidate") - - // IE workaround: write into byte array first. not sure if eiher of these IE hack are needed or just angry monkey routines - ByteArrayOutputStream baos = createTemporaryOutputStream(); - Exporter exporter = createExporter(format, print, baos) - exporter.exportReport() - - // Write length (determined via byte array). - response.setContentLength(baos.size()); - - // Flush byte array to servlet output stream. - ServletOutputStream out = response.getOutputStream(); - baos.writeTo(out); - out.flush(); - } - - - /** - * Create a JasperReports exporter for a specific output format - */ - Exporter createExporter(ReportFormat format, JasperPrint print, Object output){ - JasperUtils.createExporter(format, print, output) - } + /** + * The key of the model parameter that holds the format key. + */ + String formatKey = "format" + + /** + * the passed in report format from formatKey in model + */ + //ReportFormat format + + /** + * Stores the mappings of mapping keys to Content-Disposition header values. + */ + Properties contentDispositionMappings + + @Override + public String getContentType() { + throw new MissingFieldException("Use model and ReportFormat, contentType no longer valid ", "contentType", this.class) + } + + /** + * Set the mappings of {@code Content-Disposition} header values to + * mapping keys. If specified, Spring will look at these mappings to determine + * the value of the {@code Content-Disposition} header for a given + * format mapping. + */ + public void setContentDispositionMappings(Properties mappings) { + this.contentDispositionMappings = mappings + } + + /** + * Return the mappings of {@code Content-Disposition} header values to + * mapping keys. Mainly available for configuration through property paths + * that specify individual keys. + */ + public Properties getContentDispositionMappings() { + if (this.contentDispositionMappings == null) { + this.contentDispositionMappings = new Properties() + } + return this.contentDispositionMappings + } + + /** + * renders outside of a request Web environment + * @param model + * @param output the writer or stream you want to render to. + * @return null if output was passed , or the temp file if output was null + */ + public void render(ReportFormat format, Map params, Collection data, Object output) { + params << [data: data, format: format] + render(params, output) + } + + /** + * renders outside of a request Web environment + * @param model + * @param output the writer or stream you want to render to. + * @return null if output was passed , or the temp file if output was null + */ + public void render(Map model, Object output) { + setupFormat(model) + //TODO should we still in case stuff was set that we want passed through? + //Map mergedModel = createMergedOutputModel(model, request, response) + //prepareResponse(request, response) + + // TODO how to get subReports + //exposeSubReports(model) + // Expose Spring-managed Locale and MessageSource. + //TODO how to get localization into the report + //exposeLocalizationContext(model, request) + + JasperPrint print = fillReport(model) + JasperUtils.render(model.format as ReportFormat, print, output) + } + + /** + * This is the main method that Grails/Spring calls to render the view in the MVC context + * @param model + * @param request + * @param response + * @throws Exception + */ + @Override + public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + setupFormat(model, response) + + super.render(model, request, response) + /** + the super is in AbstractView and calls + Map mergedModel = createMergedOutputModel(model, request, response) + prepareResponse(request, response) + renderMergedOutputModel(mergedModel, getRequestToExpose(request), response) + ^ is in AbstractJasperReportsView and calls + exposeSubReports(model) + exposeLocalizationContext(model, request) + JasperPrint filledReport = fillReport(model) + postProcessReport(filledReport, model) + populateHeaders(response) + renderReport(filledReport, model, response) + + */ + } + + @CompileStatic(TypeCheckingMode.SKIP) + public void setupFormat(Map model, HttpServletResponse response = null) { + + //if the model has one then use that as the override + if (model[formatKey]) { + def fmat = model[formatKey] + model[formatKey] = fmat instanceof ReportFormat ? fmat : ReportFormat.get(fmat) + } + + if (response && !model[formatKey]) { + //use the one that grails puts in the response + model[formatKey] = ReportFormat.get(response.format) + } + //if format is null still then just use html + model[formatKey] = model[formatKey] ?: ReportFormat.HTML + + if (model[formatKey] == ReportFormat.HTML + && !model.containsKey(JRParameter.IS_IGNORE_PAGINATION)) { + model.put(JRParameter.IS_IGNORE_PAGINATION, true) + } + } + + /** + * Locates the format key in the model using the configured discriminator key and uses this + * key to lookup the appropriate view class from the mappings. The rendering of the + * report is then delegated to an instance of that view class. + */ + @Override + @CompileStatic(TypeCheckingMode.SKIP) + protected void renderReport(JasperPrint populatedReport, Map model, HttpServletResponse response) + throws Exception { + + log.debug("Rendering report using format mapping key [$model.format]") + //contentType = format.mimeType + + populateContentDispositionIfNecessary(response, model[formatKey].extension) + + if (model[formatKey].downloadContent) { + renderReportUsingOutputStream(populatedReport, response, model.format) + } else { + renderReportUsingWriter(populatedReport, response, model.format) + } + + } + + /** + * Adds/overwrites the {@code Content-Disposition} header value with the format-specific + * value if the mappings have been specified and a valid one exists for the given format. + * @param response the {@code HttpServletResponse} to set the header in + * @param format the format key of the mapping + * @see #setContentDispositionMappings + */ + private void populateContentDispositionIfNecessary(HttpServletResponse response, String format) { + if (this.contentDispositionMappings != null) { + String header = this.contentDispositionMappings.getProperty(format) + if (header != null) { + if (logger.isDebugEnabled()) { + logger.debug("Setting Content-Disposition header to: [" + header + "]") + } + response.setHeader(AbstractJasperReportsView.HEADER_CONTENT_DISPOSITION, header) + } + } + } + + /** + * We need to write text to the response Writer. + * @param print the populated {@code JasperPrint} to render + * @param response the HTTP response the report should be rendered to + * @throws Exception if rendering failed + */ + @CompileStatic(TypeCheckingMode.SKIP) + protected void renderReportUsingWriter(JasperPrint print, HttpServletResponse response, ReportFormat format) throws Exception { + + JRAbstractExporter exporter = (JRAbstractExporter) createExporter(format, print, response.getWriter()) + // Copy the encoding configured for the report into the response. + String contentType = format.mimeType + String encoding = (exporter.exporterOutput as WriterExporterOutput).getEncoding() + if (encoding) { + // Only apply encoding if content type is specified but does not contain charset clause already. + if (contentType != null && !contentType.toLowerCase().contains(WebUtils.CONTENT_TYPE_CHARSET_PREFIX)) { + contentType = contentType + WebUtils.CONTENT_TYPE_CHARSET_PREFIX + encoding + } + } + response.setContentType(contentType) + + exporter.exportReport() + } + + /** + * We need to write binary output to the response OutputStream. + * @param exporter the JasperReports exporter to use + * @param populatedReport the populated {@code JasperPrint} to render + * @param response the HTTP response the report should be rendered to + * @throws Exception if rendering failed + */ + protected void renderReportUsingOutputStream(JasperPrint print, HttpServletResponse response, ReportFormat format) throws Exception { + response.setContentType(format.mimeType) + + //workaround for an IE bug when sending download content via HTTPS. + //Copied from AbstractView.prepareResponse + response.setHeader("Pragma", "private") + response.setHeader("Cache-Control", "private, must-revalidate") + + // IE workaround: write into byte array first. not sure if eiher of these IE hack are needed or just angry monkey routines + ByteArrayOutputStream baos = createTemporaryOutputStream() + Exporter exporter = createExporter(format, print, baos) + exporter.exportReport() + + // Write length (determined via byte array). + response.setContentLength(baos.size()) + + // Flush byte array to servlet output stream. + ServletOutputStream out = response.getOutputStream() + baos.writeTo(out) + out.flush() + } + + /** + * Create a JasperReports exporter for a specific output format + */ + Exporter createExporter(ReportFormat format, JasperPrint print, Object output) { + JasperUtils.createExporter(format, print, output) + } } diff --git a/plugin/src/main/groovy/nine/jasper/spring/JasperViewResolver.groovy b/plugin/src/main/groovy/nine/jasper/spring/JasperViewResolver.groovy index e28911b..112c1cf 100644 --- a/plugin/src/main/groovy/nine/jasper/spring/JasperViewResolver.groovy +++ b/plugin/src/main/groovy/nine/jasper/spring/JasperViewResolver.groovy @@ -1,7 +1,7 @@ /* * Copyright 2009-2011 the original author or authors. * - * Licensed under the Apache License, Version 2.0 (the "License"); + * Licensed under the Apache License, Version 2.0 (the "License") * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * @@ -34,20 +34,18 @@ import javax.sql.DataSource * This uses the {@link grails.plugin.viewtools.ViewResourceLocator} to locate the resource * * This gets used simply by registering it as a spring bean - * jasperViewResolver(JasperViewResolver){ - * viewResourceLocator = ref("viewResourceLocator") + * jasperViewResolver(JasperViewResolver){* viewResourceLocator = ref("viewResourceLocator") * jdbcDataSource = ref("dataSource") * reportDataKey = "datasource" * viewNames = ["*.jasper","*.jrxml"] as String[] * viewClass = JasperReportsMultiFormatView.class * order = 20 - * } - * + *}* * @author Joshua Burnett */ @Slf4j @CompileStatic -public class JasperViewResolver extends LoaderUrlBasedViewResolver { +public class JasperViewResolver extends LoaderUrlBasedViewResolver { //injected autowired DataSource dataSource @@ -61,22 +59,22 @@ public class JasperViewResolver extends LoaderUrlBasedViewResolver { Properties headers - //Map exporterParameters = new HashMap(); + //Map exporterParameters = new HashMap() /** * Requires the view class to be a subclass of {@link AbstractJasperReportsView}. */ @Override protected Class requiredViewClass() { - return AbstractJasperReportsView.class; + return AbstractJasperReportsView.class } - - @Override //Overriden for logging + @Override + //Overriden for logging public View resolveViewName(String viewName, Locale locale) throws Exception { log.debug("resolveViewName with $viewName") - return super.resolveViewName(viewName,locale); + return super.resolveViewName(viewName, locale) } /** @@ -85,10 +83,10 @@ public class JasperViewResolver extends LoaderUrlBasedViewResolver { * @param jr * @return */ - public AbstractJasperReportsView getView(JasperReport jr){ + public AbstractJasperReportsView getView(JasperReport jr) { AbstractJasperReportsView view = (AbstractJasperReportsView) buildView("JasperReport_Populated_JasperView") view.url = null - view = (AbstractJasperReportsView) applicationContext.autowireCapableBeanFactory.initializeBean(view, "JasperReport_Populated_JasperView"); + view = (AbstractJasperReportsView) applicationContext.autowireCapableBeanFactory.initializeBean(view, "JasperReport_Populated_JasperView") //order is important here as the initializeBean calls initApplicationContext which nulls the report out view.report = jr view @@ -96,16 +94,17 @@ public class JasperViewResolver extends LoaderUrlBasedViewResolver { @CompileDynamic @Override + @SuppressWarnings(['UnnecessaryObjectReferences']) protected AbstractUrlBasedView buildView(String viewName) throws Exception { - AbstractJasperReportsView view = (AbstractJasperReportsView) super.buildView(viewName); + AbstractJasperReportsView view = (AbstractJasperReportsView) super.buildView(viewName) view.reportDataKey = reportDataKey view.subReportUrls = subReportUrls view.subReportDataKeys = subReportDataKeys view.headers = headers - //view.setExporterParameters(this.exporterParameters); + //view.setExporterParameters(this.exporterParameters) view.jdbcDataSource = dataSource view.formatKey = formatKey - return view; + return view } } diff --git a/plugin/src/main/groovy/nine/reports/DomainMetaUtils.groovy b/plugin/src/main/groovy/nine/reports/DomainMetaUtils.groovy index 1e568c8..b6cae10 100644 --- a/plugin/src/main/groovy/nine/reports/DomainMetaUtils.groovy +++ b/plugin/src/main/groovy/nine/reports/DomainMetaUtils.groovy @@ -32,26 +32,27 @@ class DomainMetaUtils { * @param columnTitles a list of overrides for titel labels, keyed off of the fields list * @return */ + @SuppressWarnings(['ThrowRuntimeException']) @CompileDynamic - static Map getFieldMetadata(PersistentEntity domainClass, List fields, Map columnTitles = null) { - Map columns = [:] + static Map getFieldMetadata(PersistentEntity domainClass, List fields, Map columnTitles = null) { + Map columns = [:] fields.each { propertyName -> //Map colProps = [fieldName:propertyName] FieldMetadata fld = new FieldMetadata(propertyName) PersistentProperty property = getPropertyByName(domainClass, propertyName) - if(!property) { + if (!property) { throw new RuntimeException("Invalid property name $propertyName for domain $domainClass.name") } Class dcPropType = property.type Class propertyType //assert Boolean.class.getName() == "foo" - List ctypes = [Boolean,Integer,Long,BigDecimal,Short,Float,Double,Byte,Character,Date,String,List] + List ctypes = [Boolean, Integer, Long, BigDecimal, Short, Float, Double, Byte, Character, Date, String, List] - for(Class clazz : ctypes){ - if(isAssignableOrConvertibleFrom(clazz, dcPropType)){ + for (Class clazz : ctypes) { + if (isAssignableOrConvertibleFrom(clazz, dcPropType)) { //assert clazz.getName() == "foo" //colProps['clazz'] = clazz.class //TODO implement type short population @@ -62,20 +63,20 @@ class DomainMetaUtils { } //set default width of 4 as a ratio fld.width = 20 - switch (fld.typeClass){ - case [Boolean,Character,Byte]: + switch (fld.typeClass) { + case [Boolean, Character, Byte]: fld.width = 15 break - case [Date,Integer,Short]: + case [Date, Integer, Short]: fld.width = 20 break case [String]: fld.width = 30 } String colTitle = columnTitles?.get(propertyName) - if(colTitle){ + if (colTitle) { fld.title = columnTitles?.get(propertyName) - }else{ + } else { fld.title = getNaturalTitle(propertyName) } @@ -90,31 +91,31 @@ class DomainMetaUtils { * @return */ @CompileDynamic - static PersistentEntity findDomainClass(String name){ + static PersistentEntity findDomainClass(String name) { - if(name.indexOf('.') == -1){ + if (name.indexOf('.') == -1) { String propertyName = GrailsNameUtils.getPropertyName(name) - Holders.grailsApplication.mappingContext.persistentEntities.find({ + Holders.grailsApplication.mappingContext.persistentEntities.find{ it.decapitalizedName == propertyName - }) - }else{ + } + } else { return Holders.grailsApplication.mappingContext.getPersistentEntity(name) } } + @SuppressWarnings(['ThrowRuntimeException']) //See https://github.com/grails/grails-core/issues/10978 static PersistentProperty getPropertyByName(PersistentEntity entity, String name) { - if(name != null && name.contains(".")) { + if (name?.contains(".")) { int indexOfDot = name.indexOf('.') String basePropertyName = name.substring(0, indexOfDot) PersistentProperty property = entity.getPropertyByName(basePropertyName) - if(property instanceof Association) { - PersistentEntity association = ((Association)property).getAssociatedEntity() + if (property instanceof Association) { + PersistentEntity association = ((Association) property).getAssociatedEntity() String restOfPropertyName = name.substring(indexOfDot + 1) return getPropertyByName(association, restOfPropertyName) - } - else { + } else { throw new RuntimeException("Property $basePropertyName of class $entity.javaClass.name is not an association") } @@ -123,33 +124,27 @@ class DomainMetaUtils { } } - /** * Converts a property name into its natural title equivalent eg ('firstName' becomes 'First Name') * customer.name = Customer (drops off the .name). product.code = Product Code , * @return */ @CompileDynamic - static String getNaturalTitle(String text){ + static String getNaturalTitle(String text) { text = text.endsWith(".name") ? text[0.. it[2].toUpperCase() } ) + text = text.replaceAll("(\\.)([A-Za-z0-9])") { Object[] it -> it[2].toUpperCase() } //text return GrailsNameUtils.getNaturalName(text) } - /** * Orders by the specified property name and direction * takes invoice.customer.name and builds a closure that looke like * - * invoice { - * customer { - * order(name) - * } - * } - * and then calls the that closure on this. + * invoice {* customer {* order(name) + *}*}* and then calls the that closure on this. * * @param propertyName The property name to order by * @param direction Either "asc" for ascending or "desc" for descending @@ -159,10 +154,9 @@ class DomainMetaUtils { */ @CompileDynamic static Closure orderNested(String propertyName, String direction) { - if(!propertyName.contains('.')) { + if (!propertyName.contains('.')) { return { order(propertyName, direction) } - } - else { + } else { def props = propertyName.split(/\./) as List def last = props.pop() Closure toDo = { order(last, direction) } @@ -174,10 +168,10 @@ class DomainMetaUtils { } @CompileDynamic - static Closure orderNested(List groupFields, callingDelegate) { + static Closure orderNested(List groupFields, Closure callingDelegate) { return { groupFields.each { - def o = orderNested(it,'asc') + def o = orderNested(it, 'asc') o.delegate = callingDelegate o() } diff --git a/plugin/src/main/groovy/nine/reports/FieldMetadata.groovy b/plugin/src/main/groovy/nine/reports/FieldMetadata.groovy index 6e44cf6..436d746 100644 --- a/plugin/src/main/groovy/nine/reports/FieldMetadata.groovy +++ b/plugin/src/main/groovy/nine/reports/FieldMetadata.groovy @@ -5,9 +5,9 @@ package nine.reports */ class FieldMetadata implements Serializable { - public FieldMetadata(){} + public FieldMetadata() {} - public FieldMetadata(String property){ + public FieldMetadata(String property) { this.property = property } /** @@ -65,8 +65,8 @@ class FieldMetadata implements Serializable { */ Object builder - Boolean isBooleanType(){ - if(typeClass == java.lang.Boolean || typeClassName == 'java.lang.Boolean'){ + Boolean isBooleanType() { + if (typeClass == java.lang.Boolean || typeClassName == 'java.lang.Boolean') { return true } } diff --git a/plugin/src/main/groovy/nine/reports/ReportFormat.groovy b/plugin/src/main/groovy/nine/reports/ReportFormat.groovy index 03eb6f1..7c80693 100644 --- a/plugin/src/main/groovy/nine/reports/ReportFormat.groovy +++ b/plugin/src/main/groovy/nine/reports/ReportFormat.groovy @@ -4,28 +4,27 @@ import groovy.transform.CompileStatic @CompileStatic enum ReportFormat { - PDF("application/pdf",true), + PDF("application/pdf", true), HTML("text/html"), PNG("text/html"), //XML("text/xml"), //JSON("text/json"), - CSV("text/csv",true), + CSV("text/csv", true), //XLS("application/vnd.ms-excel",true), TEXT("text/plain"), //DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document",true), - XLSX("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",true) + XLSX("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", true) String mimeType //whether to set up cache headers to download or just stream to browser boolean downloadContent = false - private ReportFormat(String mimeType, boolean downloadContent = false) { this.mimeType = mimeType this.downloadContent = downloadContent } - String getExtension(){ + String getExtension() { name().toLowerCase() } @@ -35,7 +34,7 @@ enum ReportFormat { public static ReportFormat get(nm) { try { return valueOf(nm.toString().toUpperCase()) - }catch (IllegalArgumentException e) { + } catch (IllegalArgumentException e) { return null } } @@ -44,4 +43,4 @@ enum ReportFormat { ReportFormat.values()*.name() } -} \ No newline at end of file +} diff --git a/plugin/src/test/groovy/jrsamples/datasource/CustomBean.groovy b/plugin/src/test/groovy/jrsamples/datasource/CustomBean.groovy index 4914281..4c46339 100644 --- a/plugin/src/test/groovy/jrsamples/datasource/CustomBean.groovy +++ b/plugin/src/test/groovy/jrsamples/datasource/CustomBean.groovy @@ -21,41 +21,40 @@ * You should have received a copy of the GNU Lesser General Public License * along with JasperReports. If not, see . */ -package jrsamples.datasource; +package jrsamples.datasource /** * @author Teodor Danciu (teodord@users.sourceforge.net) */ class CustomBean { - String city - Integer id - String name - String street - BigDecimal rate - Currency currency - - - /** - * - */ - public CustomBean(String pcity, Integer pid, String pname, String pstreet,BigDecimal rate, String cur) - { - city = pcity; - id = pid; - name = pname; - street = pstreet; - this.rate = rate - currency = Currency.getInstance(cur) - } - - - /** - * - */ - public CustomBean getMe() { - return this; - } + String city + Integer id + String name + String street + BigDecimal rate + Currency currency + + + /** + * + */ + public CustomBean(String pcity, Integer pid, String pname, String pstreet,BigDecimal rate, String cur) + { + city = pcity; + id = pid; + name = pname; + street = pstreet; + this.rate = rate + currency = Currency.getInstance(cur) + } + + + /** + * + */ + public CustomBean getMe() { + return this; + } } - diff --git a/plugin/src/test/groovy/jrsamples/datasource/CustomBeanFactory.groovy b/plugin/src/test/groovy/jrsamples/datasource/CustomBeanFactory.groovy index 4c60528..354d3a7 100644 --- a/plugin/src/test/groovy/jrsamples/datasource/CustomBeanFactory.groovy +++ b/plugin/src/test/groovy/jrsamples/datasource/CustomBeanFactory.groovy @@ -33,59 +33,59 @@ import java.util.Map; */ class CustomBeanFactory { - private static CustomBean[] data =[ - new CustomBean("Berne", new Integer(9), "James Schneider", "277 Seventh Av.",35,"EUR"), - new CustomBean("Berne", new Integer(22), "Bill Ott", "250 - 20th Ave.",25,"USD"), - new CustomBean("Boston", new Integer(23), "Julia Heiniger", "358 College Av.",55,"USD"), - new CustomBean("Boston", new Integer(32), "Michael Ott", "339 College Av.",175,"USD"), - new CustomBean("Chicago", new Integer(39), "Mary Karsen", "202 College Av.",100,"USD"), - new CustomBean("Chicago", new Integer(35), "George Karsen", "412 College Av.",100,"EUR"), - new CustomBean("Chicago", new Integer(11), "Julia White", "412 Upland Pl.",100,"USD"), - new CustomBean("Dallas", new Integer(47), "Janet Fuller", "445 Upland Pl.",100,"USD"), - new CustomBean("Dallas", new Integer(43), "Susanne Smith", "2 Upland Pl.",50,"USD"), - new CustomBean("Dallas", new Integer(40), "Susanne Miller", "440 - 20th Ave.",100,"EUR"), - new CustomBean("Dallas", new Integer(36), "John Steel", "276 Upland Pl.",100,"USD"), - new CustomBean("Dallas", new Integer(37), "Michael Clancy", "19 Seventh Av.",100,"USD"), - new CustomBean("Dallas", new Integer(19), "Susanne Heiniger", "86 - 20th Ave.",50,"USD"), - new CustomBean("Dallas", new Integer(10), "Anne Fuller", "135 Upland Pl.",100,"EUR"), - new CustomBean("Dallas", new Integer(4), "Sylvia Ringer", "365 College Av.",100,"USD"), - new CustomBean("Dallas", new Integer(0), "Laura Steel", "429 Seventh Av.",100,"USD"), - new CustomBean("Lyon", new Integer(38), "Andrew Heiniger", "347 College Av.",50,"EUR"), - new CustomBean("Lyon", new Integer(28), "Susanne White", "74 - 20th Ave.",100,"USD"), - new CustomBean("Lyon", new Integer(17), "Laura Ott", "443 Seventh Av.",100,"USD"), - new CustomBean("Lyon", new Integer(2), "Anne Miller", "20 Upland Pl.",50,"USD"), - new CustomBean("New York", new Integer(46), "Andrew May", "172 Seventh Av.",100,"EUR"), - new CustomBean("New York", new Integer(44), "Sylvia Ott", "361 College Av.",100,"USD"), - new CustomBean("New York", new Integer(41), "Bill King", "546 College Av.",50,"USD"), - new CustomBean("Oslo", new Integer(45), "Janet May", "396 Seventh Av.",100,"EUR"), - new CustomBean("Oslo", new Integer(42), "Robert Ott", "503 Seventh Av.",100,"USD"), - new CustomBean("Paris", new Integer(25), "Sylvia Steel", "269 College Av.",50,"USD"), - new CustomBean("Paris", new Integer(18), "Sylvia Fuller", "158 - 20th Ave.",100,"EUR"), - new CustomBean("Paris", new Integer(5), "Laura Miller", "294 Seventh Av.",100,"USD"), - new CustomBean("San Francisco", new Integer(48), "Robert White", "549 Seventh Av.",100,"USD"), - new CustomBean("San Francisco", new Integer(7), "James Peterson", "231 Upland Pl.",50,"EUR") - ] - + private static CustomBean[] data =[ + new CustomBean("Berne", new Integer(9), "James Schneider", "277 Seventh Av.",35,"EUR"), + new CustomBean("Berne", new Integer(22), "Bill Ott", "250 - 20th Ave.",25,"USD"), + new CustomBean("Boston", new Integer(23), "Julia Heiniger", "358 College Av.",55,"USD"), + new CustomBean("Boston", new Integer(32), "Michael Ott", "339 College Av.",175,"USD"), + new CustomBean("Chicago", new Integer(39), "Mary Karsen", "202 College Av.",100,"USD"), + new CustomBean("Chicago", new Integer(35), "George Karsen", "412 College Av.",100,"EUR"), + new CustomBean("Chicago", new Integer(11), "Julia White", "412 Upland Pl.",100,"USD"), + new CustomBean("Dallas", new Integer(47), "Janet Fuller", "445 Upland Pl.",100,"USD"), + new CustomBean("Dallas", new Integer(43), "Susanne Smith", "2 Upland Pl.",50,"USD"), + new CustomBean("Dallas", new Integer(40), "Susanne Miller", "440 - 20th Ave.",100,"EUR"), + new CustomBean("Dallas", new Integer(36), "John Steel", "276 Upland Pl.",100,"USD"), + new CustomBean("Dallas", new Integer(37), "Michael Clancy", "19 Seventh Av.",100,"USD"), + new CustomBean("Dallas", new Integer(19), "Susanne Heiniger", "86 - 20th Ave.",50,"USD"), + new CustomBean("Dallas", new Integer(10), "Anne Fuller", "135 Upland Pl.",100,"EUR"), + new CustomBean("Dallas", new Integer(4), "Sylvia Ringer", "365 College Av.",100,"USD"), + new CustomBean("Dallas", new Integer(0), "Laura Steel", "429 Seventh Av.",100,"USD"), + new CustomBean("Lyon", new Integer(38), "Andrew Heiniger", "347 College Av.",50,"EUR"), + new CustomBean("Lyon", new Integer(28), "Susanne White", "74 - 20th Ave.",100,"USD"), + new CustomBean("Lyon", new Integer(17), "Laura Ott", "443 Seventh Av.",100,"USD"), + new CustomBean("Lyon", new Integer(2), "Anne Miller", "20 Upland Pl.",50,"USD"), + new CustomBean("New York", new Integer(46), "Andrew May", "172 Seventh Av.",100,"EUR"), + new CustomBean("New York", new Integer(44), "Sylvia Ott", "361 College Av.",100,"USD"), + new CustomBean("New York", new Integer(41), "Bill King", "546 College Av.",50,"USD"), + new CustomBean("Oslo", new Integer(45), "Janet May", "396 Seventh Av.",100,"EUR"), + new CustomBean("Oslo", new Integer(42), "Robert Ott", "503 Seventh Av.",100,"USD"), + new CustomBean("Paris", new Integer(25), "Sylvia Steel", "269 College Av.",50,"USD"), + new CustomBean("Paris", new Integer(18), "Sylvia Fuller", "158 - 20th Ave.",100,"EUR"), + new CustomBean("Paris", new Integer(5), "Laura Miller", "294 Seventh Av.",100,"USD"), + new CustomBean("San Francisco", new Integer(48), "Robert White", "549 Seventh Av.",100,"USD"), + new CustomBean("San Francisco", new Integer(7), "James Peterson", "231 Upland Pl.",50,"EUR") + ] - /** - * - */ - public static Object[] getBeanArray() - { - return data; - } + /** + * + */ + public static Object[] getBeanArray() + { + return data; + } - /** - * - */ - public static Collection getBeanCollection() - { - return Arrays.asList(data); - } - static List listMap = [ - [city:"Berne", id:22, name:"Bill Ott", street:"250 - 20th Ave.", country:[name:"US"]], - [city:"Chicago", id:1, name:"Joshua Burnett", street:"22 3rd", country:[name:"US"]] - ] + /** + * + */ + public static Collection getBeanCollection() + { + return Arrays.asList(data); + } + + static List listMap = [ + [city:"Berne", id:22, name:"Bill Ott", street:"250 - 20th Ave.", country:[name:"US"]], + [city:"Chicago", id:1, name:"Joshua Burnett", street:"22 3rd", country:[name:"US"]] + ] } diff --git a/plugin/src/test/groovy/jrsamples/datasource/NestPropsSpec.groovy b/plugin/src/test/groovy/jrsamples/datasource/NestPropsSpec.groovy index 066cc9e..c939a93 100644 --- a/plugin/src/test/groovy/jrsamples/datasource/NestPropsSpec.groovy +++ b/plugin/src/test/groovy/jrsamples/datasource/NestPropsSpec.groovy @@ -15,7 +15,7 @@ import spock.lang.Specification class NestPropsSpec extends Specification implements GrailsUnitTest { void "test this"() { - expect: + expect: runReport() //print() pdf() diff --git a/plugin/src/test/groovy/jrsamples/datasource/RunCustomSpec.groovy b/plugin/src/test/groovy/jrsamples/datasource/RunCustomSpec.groovy index 451a336..57ec1eb 100644 --- a/plugin/src/test/groovy/jrsamples/datasource/RunCustomSpec.groovy +++ b/plugin/src/test/groovy/jrsamples/datasource/RunCustomSpec.groovy @@ -19,7 +19,7 @@ class RunCustomSpec extends Specification implements GrailsUnitTest{ void "test something"() { - expect: + expect: runReport() //print() pdf() diff --git a/settings.gradle b/settings.gradle index 4fdd541..9f80ea9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,4 +7,4 @@ include 'examples/app' findProject(':examples/app').name = 'test-app' include 'examples/sandbox-dynamic-jasper' -findProject(':examples/sandbox-dynamic-jasper').name = 'dynamic-jasper' \ No newline at end of file +findProject(':examples/sandbox-dynamic-jasper').name = 'dynamic-jasper' diff --git a/version.properties b/version.properties new file mode 100644 index 0000000..e057c31 --- /dev/null +++ b/version.properties @@ -0,0 +1,8 @@ +#Version of the produced binaries. This file is intended to be checked-in. +#It will be automatically bumped by release automation. +version=3.1.1 +previousVersion=3.1.0 +#yakworks addon to shipkit. when this gets set to false then will do 'performRelease' and then set back to true. +#when this is true then it just does a 'publish' task which sends to artifactory +snapshot=true + From 9e059647a3bbe48c1294c89e879d7f787d5675f8 Mon Sep 17 00:00:00 2001 From: sudhir nimavat Date: Wed, 17 Apr 2019 20:56:30 +0530 Subject: [PATCH 2/2] Add idea editorconfig --- .editorconfig | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ae7b231 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,54 @@ +root = true + +[*] +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +max_line_length=100 + +[*.coffee] +indent_style = space +indent_size = 2 + +[*.js] +indent_style = space +indent_size = 2 + +[{*.yml,*.yaml}] +indent_style = space +indent_size = 2 + +[*.css] +indent_style = space +indent_size = 2 + +[*.styl] +indent_style = space +indent_size = 2 + +[*.html] +indent_style = space +indent_size = 4 + +[*.groovy] +indent_style = space +indent_size = 4 + +[*.gsp] +indent_style = space +indent_size = 4 + +[*.gradle] +indent_style = space +indent_size = 4 + +[*.md] +trim_trailing_whitespace = false + +# Stylint - https://rosspatton.github.io/stylint/ +[{package.json,.stylintrc}] +indent_size = 2 + +[*.json] +indent_size = 2