Corda RPC client external dependencies - java

Suppose I have a small RPC client application for corda, which should be uploaded into node, and be called to do some utility work on node.
In build.gradle file of my utility RPC client I have just the following dependency cordaCompile "$corda_release_group:corda-rpc:$corda_release_version" and my JAR task looks like this
jar {
version = ''
baseName = 'rpc_utility'
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
manifest {
attributes 'Main-Class': 'com.example.rpcclient.MainKt'
}
zip64=true
from { (configurations.compile).collect { it.isDirectory() ? it : zipTree(it) } }
}
but when I create my jar, it results in 58 MB Jar file, with all the dependencies of Corda in it, which are already there inside the node, packed in the corda.jar file. And cordapps can use these libraries without having them inside their JAR files.
Now the question is, how should I configure my jar task and what should I include inside it to tell Java that all the dependencies it needs are right there, in the same folder inside corda.jar file.
P.S. I also tried to create a fat jar like I do now, and then minify it with Proguard, but even after a long proguard-rules list I still have errors, as Proguard seems to remove a lot of files that Corda needs, so this seems to be not a good solution, and even if I succeed, I will get a ~20 MB file, just for a few lines of code that I have in real...

The client jar is about the right size. It not only includes the dependencies for Corda but also includes your actual CorDapp jars as well (Contract & workflows). The reason is that theļ¼š
RPC client needs to talk to the Corda node, so it needs the Corda dependencies.
It also needs to understand your CorDapps as your controller will invoke the flow directly.

Related

Set a variable value within a jar using a gradle task

I have a client and server architecture.
The client is a runnable .jar file built using the following Gradle task:
jar {
archiveName = "app.jar"
from sourceSets.main.output.classesDir
include '**/*.class'
manifest {
attributes 'Main-Class': 'com.bobbyrne01.app.Main'
}
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}
I'm making a change to how this client will authenticate.
The problem is, I'd like to specify which method of authentication the client should use during the build.
So that when the user downloads the .jar, they will just run it and whichever method of authentication I activated during the build will be active in the .jar.
What would be the best way to set this authenticationType variable/flag?
For the server, there is an interface for authentication and a number of classes which implement different authentication methods. While building the server, I specify a gradle property which gets set as an environment variable on the docker image.
So at runtime, the server uses reflection to determine which authentication class to instantiate.
But I'm unsure how I can set a similar value within the jar.
Use a properties file containing a value allowing to decide, at runtime, which authentication mechanism you want to use.
Define it as
authentication=${authentication} or
or
authentication=##authentication##
in the source properties file. And use expand or filter in the standard processResources gradle task (of type Copy) in order to replace the placeholder by the actual value you want to use.
See https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Copy.html#org.gradle.api.tasks.Copy:expand(java.util.Map) and https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Copy.html#org.gradle.api.tasks.Copy:filter(java.util.Map,%20java.lang.Class).

Gradle copy command deprecated, breaks build

In Gradle 3.x I was able to get some xml mapping files to copy into the classes directory prior to build/jar via the following block:
copy{
from 'src/main/java/com/company/mapping'
into 'build/classes/main/java/com/company/mapping'
include '**/*.xml'
}
In Gradle 4.9 this has been deprecated in favor of:
task copyMappings(type: Copy){
from 'src/main/java/com/company/mapping'
into 'build/classes/main/java/com/company/mapping'
include '**/*.xml'
}
The copyMappings task succeeds, but build/jar does not wait for copyMappings to finish. I have tried variations on build.dependsOn and doFirst{ copyMappings } doLast{ build } but nothing seems to get me the desired effect of having the copied files in place in the 'into' path prior to jar.
This is for Windows 10.
This works for me with Gradle 4.9 on Mac OS:
apply plugin: 'java'
task copyMappings(type: Copy) {
from 'src/main/java/com/company/mapping'
into 'build/classes/main/java/com/company/mapping'
include '**/*.xml'
}
jar.dependsOn copyMappings
jar.doFirst {
assert new File("${projectDir}/build/classes/main/java/com/company/mapping/abc.xml").exists()
assert new File("${projectDir}/build/classes/main/java/com/company/mapping/def.xml").exists()
}
command line is gradle clean jar
I like to model things around source sets where appropriate as doing so let's the build work more reliably with a wide range of plugins and use cases. For example, imagine you want to run an application direct from its class files and resources rather than packaging it as a JAR first. You could make sure that the "run" task depends on the copy as well, but you'd have to do that for every instance where this is a requirement.
Source sets are the ideal solution because they have the concept of a runtime classpath, which will work for packaging, instrumentation, running, testing and so on.
With that in mind, I would go for this simple declaration and get rid of the copy task:
sourceSets {
main {
resources {
srcDir "src/main/java"
include "**/*.xml"
}
}
}
The XML files will end up in a different directory from your current approach, but that shouldn't matter unless you have tasks that assume the location rather than using the source set model to get the necessary information.
Note The above include directive applies to all the resources in src/main/resources as well. So if you have properties files or text files or anything else in there, they will be excluded. The simplest solution is to add all required resource file patterns to the include directive.

Gradle copy dependencies in built jar

I'm searching a solution for adding my gradle dependencies in my built jar file.
For example, I've the dependency com.fazecast:jSerialComm and wanting to add the library in specific folder in the jar, library path should belibs/jserialcomm/jSerialComm-2.0.2.jar
Add the following to your build.gradle:
jar {
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
This will merge the content of all dependencies into the output jar.
See also http://www.baeldung.com/gradle-fat-jar.
In a different approach, one would copy the jars of the dependencies into the output jar (jars in jar), but that also requires writing a custom class loader.
UPDATE after edit of question:
The OP wants to take the second approach, which is employed as follows:
plugins {
id "com.github.onslip.gradle-one-jar" version "1.0.5"
}
task awesomeFunJar(type: OneJar) {
mainClass = 'com.github.rholder.awesome.MyAwesomeMain'
}
This will include all dependent jars into a lib directory in the output jar. It will also install a custom class loader, which loads jars from the lib directory in the jar. This is something that the standard class loader does not do, no matter how you tweak the class path.
See also https://github.com/Onslip/gradle-one-jar/

What is the main-class attribute of the build.gradle file?

I was told to include this in my build.gradle file in exercism.io in order to run my test suite in Java.
jar {
manifest {
attributes 'Main-Class': 'net.petrikainulainen.gradle.HelloWorld'
}
}
What is jar? What is the attributes 'Main-Class' doing? Is it specifying where my main class exists in the build folder?
In essence, gradle seems to be doing a few things for me:
1. creating a build folder where my Javascript compiled code exists
2. running my test suite
3. fetching any dependencies that I specify in the build.gradle file.
Is this typically what a dependency manager does?
In order to run tests you don't need to add a Main-Class attribute. What you've done there is specify that when building a jar file, include the Main-Class attribute in the jars manifest, which is the class to use as the entry when running a jar file via java -jar.
In answer to your second question, Gradle isn't a dependency manager, it's a build automation tool and yes, that's typically what they do for you.

Deploy additional files in Gradle Application Plugin

I have a small Java/Gradle project. I'm using the Application plugin to create a zip distribution (using the distZip task). Using the standard configuration I get the following directories in my zip file:
/bin - The scripts to start the application go in here
/lib - Contains my project code in a JAR file and all dependency JAR files.
The trouble is that I would like a third directory: /conf where I can put my configuration files (instead of having them packaged inside my application JAR file.
I imagine that this is a pretty common requirement because things like log4j.xml and hibernate.properties would be better placed outside the JAR file. I just can't figure out how I can customise the behavior of the Application plugin to do this however.
I revisited this problem several months later and I finally have an elegant solution. The following code should be added to the gradle file:
distZip {
into(project.name) {
from '.'
include 'conf/*'
}
}
This adds an additional include to the distZip task. This copies the "conf" directory (including contents) into the Zip distribution.
The generated zip file contains a single directory which is the same as the project name. This is why the "into" part is required.
Actually, create a dist dir under the src dir in your project. Anything in this dir is copied by the application plugin (under applicationDistribution) when installApp or distZip is run.
Or edit applicationDistribution to do other things, if a simple copy is not enough.
For me, a simple
applicationDistribution.from("src/main/config/") {
into "config"
}
did the job. Of course you need to have your properties loaded correctly from within code. Especially if you move them from src/main/resources where they have been usable via classpath, into the new location. I circumvented this by adding a command line parameter which points to the configuration file.
I am not sure whether you can customize the application plugin, I have never used it. There is however other ways to achieve what you want to achieve.
You may create a /conf directory like this:
confDir = new File("$buildDir/conf")
You can then copy the files you need into this directory like this:
task copyConfFiles(type: Copy) {
from _wherever your files reside_
into confDir
include('**/*.properties') // your configuration files
}
You may then hook this copy task into the process like this:
distZip.dependsOn copyConfFiles
And last if you do not want your configurations in the final zip, you can do this:
distZip {
exclude('**/*.properties') // your configuration files
}
Again, there might be a better way. This is a way.
OP's self-answer may be good for his use case, but there are a few things I'd like to improve on:
His answer suggests that he has a directory conf parallel to the build.gradle. There is no such thing in the Maven Standard Directory Layout. The general consensus is to have a src/main/conf as had been hinted to in the docs:
If there are other contributing sources to the artifact build, they
would be under other subdirectories: for example src/main/antlr would
contain Antlr grammar definition files.
The target directory name is NOT project.name as had been pointed out in a comment.
If resource filtering is required, and it often is, then having a separate task is desirable. During local development, this task can be run to generate the filtered files. The distribution would merely use the output of this task (and unlike OP's answer, this also makes conf available to the tar distribution).
def props = new Properties()
file("src/main/filters/application.properties")
.withInputStream { props.load(it) }
import org.apache.tools.ant.filters.ReplaceTokens
task copyConf(type: Copy) {
from("src/main/conf/")
into("$buildDir/conf")
filesMatching("**/*.y*ml") {
filter(tokens: props, ReplaceTokens)
}
}
distributions {
main {
contents {
from(copyConf) {
into("conf")
}
}
}
}

Categories

Resources