google-bigquerymoqui

Moqui script with external dependencies


I amb writing a small component which needs to pull data from a Google BigQuery table to later save that as Party.

So I created a new component for which I have a service with one single action to call a script and a script. On the component I also added a build.gradle to add the dependency to google bigquery.

Problem is that when I try to import the bigquery libraries from the script it says it can't find them.

component/mycomponent/{data,entity,screen,script,service}

mycomponent/component.xml:

<?xml version="1.0" encoding="UTF-8"?>
<component xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/moqui-conf-2.1.xsd"
    name="mycomponent" version="${moqui_version}">
</component>

mycomponent/build.gradle:

apply plugin: 'groovy'

sourceCompatibility = '1.8'
def moquiDir = file(projectDir.absolutePath + '/../../..')
def frameworkDir = file(moquiDir.absolutePath + '/framework')

// maybe in the future: repositories { mavenCentral() }
repositories {
    flatDir name: 'localLib', dirs: frameworkDir.absolutePath + '/lib'
    jcenter()
}

dependencies {
    compile project(':framework')
    testCompile project(':framework').configurations.testCompile.allDependencies
    compile 'com.google.cloud:google-cloud-bigquery:1.40.0'
}

// by default the Java plugin runs test on build, change to not do that (only run test if explicit task)
// no longer workds as of gradle 4.8 or possibly earlier, use clear() instead: check.dependsOn.remove(test)
check.dependsOn.clear()

test {
    dependsOn cleanTest
    dependsOn ':runtime:component:mantle-usl:test'

    systemProperty 'moqui.runtime', moquiDir.absolutePath + '/runtime'
    systemProperty 'moqui.conf', 'conf/MoquiDevConf.xml'
    systemProperty 'moqui.init.static', 'true'

    // show standard out and standard error of the test JVM(s) on the console
    testLogging.showStandardStreams = true; testLogging.showExceptions = true

    classpath += files(sourceSets.main.output.classesDirs)
    // filter out classpath entries that don't exist (gradle adds a bunch of these), or ElasticSearch JarHell will blow up
    classpath = classpath.filter { it.exists() }

    beforeTest { descriptor -> logger.lifecycle("Running test: ${descriptor}") }
}

mycomponent/services/myservice.xml:

<services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/service-definition-2.1.xsd">
    <service verb="sync" noun="myservice">
        <in-parameters/>
        <out-parameters/>
        <actions>
            <script location="component://mycomponent/script/pullClientesBQ.groovy" />
        </actions>
    </service>
</services>

mycomponent/script/pullClientesBQ.groovy:

import com.google.cloud.bigquery.BigQuery
import com.google.cloud.bigquery.BigQueryOptions
import com.google.cloud.bigquery.FieldValueList
import com.google.cloud.bigquery.QueryJobConfiguration
// Script code follows.

Then I go to the Tools web interface to run the service and:

17:47:13.788 ERROR 110121908-17 o.m.i.a.XmlAction Error running groovy script (org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: component___intermegaBaseClientes_script_pullClientesBQ_groovy: 1: unable to resolve class com.google.cloud.bigquery.BigQuery @ line 1, column 1. import com.google.cloud.bigquery.BigQuery

So, how can I (properly) use external libraries on my component's scripts?

thanks


Solution

  • Please see the Moqui component structure documentation here for a description of directories and files used by convention in components:

    https://www.moqui.org/docs/framework/Tool+and+Config+Overview#extensions-and-add-ons

    There was a description of the 'lib' directory there, which is how you get JAR files on the classpath in a Moqui component. I just added some additional details for supported files as well including build.gradle with notes related to this question.

    In short the real question is how to get stuff on the Java classpath and that is done using the 'classes' and 'lib' directories in a Moqui component directory. What you're missing is something in your build.gradle file to copy built and depended on JAR file to the 'lib' directory. Here is an example of something you can add to your build.gradle file to do this:

    task cleanLib(type: Delete) { delete fileTree(dir: projectDir.absolutePath+'/lib', include: '*') }
    clean.dependsOn cleanLib
    
    jar {
        destinationDir = file(projectDir.absolutePath + '/lib')
        baseName = jarBaseName
    }
    task copyDependencies { doLast {
        copy { from (configurations.runtime - project(':framework').configurations.runtime - project(':framework').jar.archivePath)
            into file(projectDir.absolutePath + '/lib') }
    } }
    copyDependencies.dependsOn cleanLib
    jar.dependsOn copyDependencies
    

    It is also a good idea to add the 'lib' directory to the .gitignore file in your component directory so JAR files there don't accidentally get added to git.