Flying Saucer JAR location

I am working on a slightly customized version of Flying Saucer (trying to integrate barcode generation, incidentally). I see the flying-saucer-core.jar and flying-saucer-pdf.jar in the tomcat/shared directory. But even if I delete those and replace them with my custom ones, when the server is restarted, the originals will return. Where can I find the directory that holds the “master JARs” (for lack of a better term) that are copied to TomCat when the server is restarted?

I only need to replace the flying-saucer-pdf file. I made changes to a single file and also switched from iText 2 to iText 5 to utilize their built in barcode generation API. How can I swap out this single file? From the Gradle logs I see it is being downloaded at some point from repo.cube-platform.com but I cannot figure out script is downloading it.

Hi.

If you want to use another version of the Flying Saucer from Maven, add the following to the coreModule dependencies in the build.gradle file:

compile group: 'org.xhtmlrenderer', name: 'flying-saucer-pdf', version: '9.1.12'
compile group: 'org.xhtmlrenderer', name: 'flying-saucer-core', version: '9.1.12'

If you want to use your one local customized version add the dependency in the following way:

files("${rootProject.projectDir}/lib/flying-saucer-pdf.jar")

If your customized version is located in your own cloud repository, you have to add this repository to the project repositories list and then add the Flying Saucer dependency to the coreModule

Thank you for the response. I think I’m at least in the right direction now. But I would lieka little more clarification. This is my build.gradle file (the pertinent info):

configure(coreModule) {

    configurations {
        jdbc
        dbscripts
    }

    dependencies {
        compile(globalModule)
        provided(servletApi)
        jdbc(postgres)
        testRuntime(postgres)
        files('C:/Users/wjones/studio-projects/DeiProductConfig2/bin/flying-saucer-pdf.jar')

    }

    .......

}

The flying-saucer-pdf.jar file is being loaded into my local tomcat deployment. However, the original flying-saucer JARs are also being loaded and the reporting module seems to use those instead of the custom one I am loading in. How would I prevent them from loading in the first place?

My modification added a check in the ITextReplacedElementFactory. When an tag is passed in, it checks the src attribute to see if it starts with “###”. If it does, the rest of the attribute is used to generate a barcode using the IText5 Barcode API which is passed as the image to use for the tag. If it doesn’t, it loads the src at normal.

Like this: <img src="###128#S-00054" height="25px"></img>

This also means that I need to use the IText5 jar file instead of the IText2 jar that is the default.

After the above change to my build.gradle file, I tried using the above barcode generation code with the following exception:

com.haulmont.reports.exception.ReportingException: . Template name [cofcTest.html] Report name [cofc]
Bad URL given: [null]
null
null
	at com.haulmont.reports.ReportingBean.createReportDocument(ReportingBean.java:341)
	at com.haulmont.reports.ReportingBean.createReportDocument(ReportingBean.java:284)
	at com.haulmont.reports.ReportingBean.createReport(ReportingBean.java:202)
	at com.haulmont.reports.ReportServiceBean.createReport(ReportServiceBean.java:45)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
	at com.haulmont.cuba.core.sys.ServiceInterceptor.aroundInvoke(ServiceInterceptor.java:117)
	at sun.reflect.GeneratedMethodAccessor140.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy266.createReport(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.haulmont.cuba.core.sys.remoting.LocalServiceInvokerImpl.invoke(LocalServiceInvokerImpl.java:94)
	at com.haulmont.cuba.web.sys.remoting.LocalServiceProxy$LocalServiceInvocationHandler.invoke(LocalServiceProxy.java:154)
	at com.sun.proxy.$Proxy60.createReport(Unknown Source)
	at com.haulmont.reports.gui.ReportGuiManager.getReportResult(ReportGuiManager.java:266)
	at com.haulmont.reports.gui.ReportGuiManager.printReportSync(ReportGuiManager.java:235)
	at com.haulmont.reports.gui.ReportGuiManager.printReportSync(ReportGuiManager.java:220)
	at com.haulmont.reports.gui.ReportGuiManager.printReport(ReportGuiManager.java:151)
	at com.company.deiproductconfig2.web.screens.customerOrder.invoice.Allinvoices.onCOfCPrintButtonClick(Allinvoices.java:244)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.haulmont.cuba.gui.xml.DeclarativeAction.actionPerform(DeclarativeAction.java:92)
	at com.haulmont.cuba.web.gui.components.WebButton.performAction(WebButton.java:44)
	at com.haulmont.cuba.web.gui.components.WebButton.lambda$new$61446b05$1(WebButton.java:36)
	at sun.reflect.GeneratedMethodAccessor302.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510)
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:200)
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:163)
	at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:1037)
	at com.vaadin.ui.Button.fireClick(Button.java:377)
	at com.haulmont.cuba.web.toolkit.ui.CubaButton.fireClick(CubaButton.java:54)
	at com.vaadin.ui.Button$1.click(Button.java:54)
	at sun.reflect.GeneratedMethodAccessor301.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:158)
	at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:119)
	at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:444)
	at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:409)
	at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:274)
	at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:90)
	at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41)
	at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1435)
	at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:361)
	at com.haulmont.cuba.web.sys.CubaApplicationServlet.serviceAppRequest(CubaApplicationServlet.java:300)
	at com.haulmont.cuba.web.sys.CubaApplicationServlet.service(CubaApplicationServlet.java:191)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:107)
	at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:73)
	at com.haulmont.cuba.web.sys.CubaHttpFilter.doFilter(CubaHttpFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)

My question is whether CUBA checks the file for proper formatting before passing it to Freemarker and then to FlyingSaucer. I am confused about this because the exception comes from the ReportingBean class and not from FlyingSaucer. If CUBA does check the src attributes before FlyingSaucer even gets its hands on it, then I don’t know how to get my change to work with the reporting module.

Hi,

CUBA doesn’t validate template before execution. Could you provide the sample project to reproduce the problem?
You can try to find the original error in the DEBUG while setting the breakpoint into the ReportingBean.java:341

Also, we have a sample for barcode/QR generation (GitHub - aleksey-stukalov/sample-report-generation: The sample shows how to use reporting add-on in the CUBA Platform (requires premium package))

sample-barcodes.zip (166.5 KB)

I realized I needed to add the IText5 jar to the project and I was able to do that successfully.

I had not thought about using a groovy script to generate the barcode. I’ll play with that as well.

I modified my baroda solution to use zxing instead of IText5. Zxing is loading fine using the gradle format posted in the barcode sample above. But I still can’t figure out how to use my version of flying saucer. It is still taking the default version.

Hi,

How to use your flying saucer:

  • Add the directory with libs to the repositories in the build.gradle:
repositories {
  
        flatDir {
            dirs "$rootProject.projectDir/libs"
        }
        
}
  • Add jar to the directory libs. Rename jar. Jar name should contain the version number, e.g. flying-saucer-pdf-9.1.7.jar
  • Add compile dependency to your lib
    compile name: 'flying-saucer-pdf-9.1.7'

Thank you,
Andrey

Sorry for the late reply. I was out of office for a month. I have my custom flying-saucer-pdf-9.1.7.345.jar file in …\DeiProductConfig2\libs. DeiProductConfig2 is my project. I have the following build.gradle file:

buildscript {
    ext.cubaVersion = '6.8.7'
    repositories {
		
		maven {
            url 'https://repo.cuba-platform.com/content/groups/work'
            credentials {
                username(rootProject.hasProperty('repoUser') ? rootProject['repoUser'] : 'cuba')
                password(rootProject.hasProperty('repoPass') ? rootProject['repoPass'] : 'cuba123')
            }
        }
        maven {
            url 'https://repo.cuba-platform.com/content/groups/premium'
            credentials {
                username(rootProject.hasProperty('premiumRepoUser') ? rootProject['premiumRepoUser'] : System.getenv('CUBA_PREMIUM_USER'))
                password(rootProject.hasProperty('premiumRepoPass') ? rootProject['premiumRepoPass'] : System.getenv('CUBA_PREMIUM_PASSWORD'))
            }
        }
		
		flatDir {
            dirs "$rootProject.projectDir/libs"
        }
    }
	
    dependencies {
        classpath "com.haulmont.gradle:cuba-plugin:$cubaVersion"
    }
}

def globalModule = project(':config-global')
def coreModule = project(':config-core')
def guiModule = project(':config-gui')
def webModule = project(':config-web')
def webThemesModule = project(':config-web-themes')

def servletApi = 'org.apache.tomcat:tomcat-servlet-api:8.0.26'



apply(plugin: 'java')
apply(plugin: 'eclipse')
apply(plugin: 'cuba')

cuba {
    artifact {
        group = 'com.company.deiproductconfig2'
        version = '0.1'
        isSnapshot = true
    }
    tomcat {
        dir = "$project.rootDir/deploy/tomcat"
        shutdownPort = 8006
    }
}

dependencies {
    appComponent("com.haulmont.cuba:cuba-global:$cubaVersion")
    appComponent("com.haulmont.reports:reports-global:$cubaVersion")

}


def postgres = 'org.postgresql:postgresql:9.4.1212'

configure([globalModule, coreModule, guiModule, webModule]) {
    apply(plugin: 'java')
    apply(plugin: 'maven')
    apply(plugin: 'eclipse')
    apply(plugin: 'cuba')

    dependencies {
        testCompile('junit:junit:4.12')
    }

    task sourceJar(type: Jar) {
        from file('src')
        classifier = 'sources'
    }

    artifacts {
        archives sourceJar
    }
}

configure(globalModule) {
    task enhance(type: CubaEnhancing)

    jar {
        manifest {
            attributes('App-Component-Id': cuba.artifact.group)
            attributes('App-Component-Version': cuba.artifact.version + (cuba.artifact.isSnapshot ? '-SNAPSHOT' : ''))
        }
    }
}

configure(coreModule) {

    configurations {
        jdbc
        dbscripts
    }

    dependencies {
        compile(globalModule)
        provided(servletApi)
        jdbc(postgres)
        testRuntime(postgres)
        compile('com.google.zxing:core:2.0')
		
		compile name: 'flying-saucer-pdf-9.1.7.345.jar'
    }

    task cleanConf(description: 'Cleans up conf directory') {
        doLast {
            def dir = new File(cuba.tomcat.dir, '/conf/config-core')
            if (dir.isDirectory()) {
                ant.delete(includeemptydirs: true) {
                    fileset(dir: dir, includes: '**/*', excludes: 'local.app.properties')
                }
            }
        }
    }

    task deploy(dependsOn: [assemble, cleanConf], type: CubaDeployment) {
        appName = 'config-core'
        appJars('config-global', 'config-core')
    }

    task createDb(dependsOn: assembleDbScripts, description: 'Creates local database', type: CubaDbCreation) {
        dbms = 'postgres'
        host = '192.168.2.19'
        dbName = 'productconfig'
        dbUser = 'postgres'
        dbPassword = 'i_h8_cat$'
    }

    task updateDb(dependsOn: assembleDbScripts, description: 'Updates local database', type: CubaDbUpdate) {
        dbms = 'postgres'
        host = '192.168.2.19'
        dbName = 'productconfig'
        dbUser = 'postgres'
        dbPassword = 'i_h8_cat$'
    }
}

configure(guiModule) {
    dependencies {
        compile(globalModule)

    }

    task deployConf(type: Copy) {
        from file('src')
        include "com/company/deiproductconfig2/**"
        into "$cuba.tomcat.dir/conf/config"
    }
}

configure(webModule) {
    configurations {
        webcontent
    }

    dependencies {
        provided(servletApi)
        compile(guiModule)

    }
    
    task webArchive(type: Zip) {
        from file("$buildDir/web")
        from file('web')
        classifier = 'web'
    }

    artifacts {
        archives webArchive
    }

    task deployConf(type: Copy) {
        from file('src')
        include "com/company/deiproductconfig2/**"
        into "$cuba.tomcat.dir/conf/config"
    }

    task clearMessagesCache(type: CubaClearMessagesCache) {
        appName = 'config'
    }
    deployConf.dependsOn clearMessagesCache

    task cleanConf(description: 'Cleans up conf directory') {
        doLast {
            def dir = new File(cuba.tomcat.dir, '/conf/config')
            if (dir.isDirectory()) {
                ant.delete(includeemptydirs: true) {
                    fileset(dir: dir, includes: '**/*', excludes: 'local.app.properties')
                }
            }
        }
    }

    task deploy(dependsOn: [assemble, cleanConf], type: CubaDeployment) {
        appName = 'config'
        appJars('config-global', 'config-gui', 'config-web')
    }
    task buildScssThemes(type: CubaWebScssThemeCreation)
    task deployThemes(type: CubaDeployThemeTask, dependsOn: buildScssThemes)
    assemble.dependsOn buildScssThemes
}

configure(webThemesModule) {
    apply(plugin: 'java')
    apply(plugin: 'maven')
    apply(plugin: 'cuba')

    appModuleType = 'web-themes'

    buildDir = file('../build/scss-themes')

    sourceSets {
        main {
            java {
                srcDir '.'
            }
            resources {
                srcDir '.'
            }
        }
    }
}





task undeploy(type: Delete, dependsOn: ':config-web:cleanConf') {
    delete("$cuba.tomcat.dir/shared")
    delete("$cuba.tomcat.dir/webapps/config-core")
    delete("$cuba.tomcat.dir/webapps/config")
}

task restart(dependsOn: ['stop', ':config-core:deploy', ':config-web:deploy'], description: 'Redeploys applications and restarts local Tomcat') {
    doLast {
        ant.waitfor(maxwait: 6, maxwaitunit: 'second', checkevery: 2, checkeveryunit: 'second') {
            not {
                socket(server: 'localhost', port: '8787')
            }
        }
        start.execute()
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '4.3.1'
}

apply from: 'extra.gradle'

task buildWar(type: CubaWarBuilding) {
    coreContextXmlPath = 'modules/core/web/META-INF/war-context.xml'
    webXmlPath = 'modules/web/web/WEB-INF/single-war-web.xml'
    appProperties = [
        'cuba.automaticDatabaseUpdate': true,
    ]
    includeContextXml = true
    includeJdbcDriver = true
    appHome = '/var/lib/tomcat8/webapps'
}

There is an error in here somewhere as it can’t start tomcat (localhost server from the Studio) with this configuration. It keeps trying to read the flying-saucer-pdf-9.1.7.345.jar file from the cuba repositories and not the my local directory with this error:

Could not resolve :flying-saucer-pdf-9.1.7.345.jar:.
Could not get resource ‘https://repo.cuba-platform.com/content/groups/premium//flying-saucer-pdf-9.1.7.345.jar//flying-saucer-pdf-9.1.7.345.jar-.pom’.
Could not GET ‘https://repo.cuba-platform.com/content/groups/premium//flying-saucer-pdf-9.1.7.345.jar//flying-saucer-pdf-9.1.7.345.jar-.pom’. Received status code 403 from server: Forbidden.

I have played with the docx2pdf report in the sample-report-generation project from above and I feel pretty confident that it cold be made to work if needed. But I feel that being able to use HTML to generate reports will be more beneficial long term as it prevents the need for the management team that will be crafting and using the reports to have to jump into groovy scripts. So please forgive me for beating this dead horse and my continuous failures to make it work.

I finally had a chance to wrap back around to this. My problem was that I was confused about in which dependencies block I needed to add the compile name: 'flying-saucer-pdf-9.1.7.345.jar'. I thought I needed to add the compile name lines to the dependencies block in the coreModule block but I finally made it work with the following:

buildscript {
    ext.cubaVersion = '6.8.7'
    repositories {
	
    ...
	
        flatDir {
            dirs "$rootProject.projectDir/libs"
        }
    }

    ...
}

....

configure([globalModule, coreModule, guiModule, webModule]) {

    ....

    dependencies {

       ....

        compile name: 'flying-saucer-pdf-9.1.7.9.8.7'
        compile name: 'core-3.3.2'
        compile name: 'javase-3.3.2'
    }

...

}

The jars need to be copied to the <sampleProject>/lib folder (if you don’t have one, create it). I opted to use the JARs of zxing so those were downloaded and copied to the same folder. This is now working for me. If you don’t feel that this needs any more information, please accept this as the answer.