Why? Sometimes you may not have access to various resources in environments in order to encapsulate all of the dependencies of your :”script” (DISCLAIMER: You’re now basically making a full blown groovy/java project). But this could also be handy if you’ve written a groovy script and want to make it into a full blown application.

In order to do this we go to: https://start.spring.io/ and generate the project, you’ll now have something like:

Spring Initializr

extract the downloaded zip file to a directory and explore the contents:

[user@localhost somescripts]$ tree .
.
├── build.gradle
├── gradle
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── HELP.md
├── settings.gradle
└── src
├── main
│   ├── groovy
│   │   └── com
│   │   └── codergists
│   │   └── somescripts
│   │   └── SomescriptsApplication.groovy
│   └── resources
│   └── application.properties
└── test
└── groovy
└── com
└── codergists
└── somescripts
└── SomescriptsApplicationTests.groovy
14 directories, 10 files

In order to keep the application up I have decided to use a web context for spring boot, so our jar will run tomcat emedded. And I have also aligned the dependencies so the project is using the redhat blessed jars for camel/fuse/springboot. Importing a maven bom does not seem to be possible using the @Grab groovy grapes. Hence why I am trying this in gradle.

Modify the build.gradle like so:

plugins {
id 'org.springframework.boot' version '2.1.4.RELEASE'
id 'groovy'
}
apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'org.springframework.boot'
group = 'com.codergists'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven{
url "https://maven.repository.redhat.com/ga"
}
}
//taken from: https://maven.repository.redhat.com/ga/org/jboss/redhat-fuse/fuse-springboot-bom/
dependencyManagement {
imports {
mavenBom 'org.jboss.redhat-fuse:fuse-springboot-bom:7.2.0.fuse-720020-redhat-00001'
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.codehaus.groovy:groovy'
implementation 'javax.servlet:javax.servlet-api'
implementation 'org.apache.camel:camel-core'
implementation 'org.apache.camel:camel-servlet'
implementation 'org.apache.camel:camel-jackson'
implementation 'org.apache.camel:camel-spring-boot-starter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
view raw build.gradle hosted with ❤ by GitHub

And also modify the src/main/groovy/SomescriptsApplication.groovy to include a set of camel routes. An IDE like IntelliJ or Eclipse would help in order to resolve the import statements. We have had to modify aspects of what we would be doing in a groovy script.

package com.codergists.somescripts
import org.springframework.boot.SpringApplication
import org.apache.camel.builder.RouteBuilder
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.apache.camel.component.servlet.CamelHttpTransportServlet
import org.springframework.boot.web.servlet.ServletRegistrationBean
import org.springframework.context.annotation.Bean
import org.apache.camel.model.rest.RestBindingMode
import org.apache.camel.LoggingLevel
import org.apache.camel.Exchange
import org.apache.camel.Processor
@SpringBootApplication
class SomescriptsApplication extends RouteBuilder {
static void main(String[] args) {
SpringApplication.run(SomescriptsApplication, args)
}
@Bean
public ServletRegistrationBean camelServletRegistrationBean() {
ServletRegistrationBean registration = new ServletRegistrationBean(new CamelHttpTransportServlet(), "/camel/*");
registration.setName("CamelServlet");
return registration;
}
@Override
public void configure() throws Exception {
restConfiguration()
.component("servlet")
.bindingMode(RestBindingMode.json);
rest().get("/hello")
.to("direct:hello");
from("direct:hello")
.log(LoggingLevel.INFO, "Hello World HTTP ENDPOINT")
.process(new Processor() {
@Override
void process(Exchange exchange) throws Exception {
def jsonMap = [hello:"world"]
exchange.in.body = jsonMap
}
})
from("timer:hello?period=5000").log('hello world timer fired ${exchangeProperty[CamelTimerCounter]}')
}
}

Running the application from gradle with ./gradlew bootRun will confirm the camel context is using the specified fuse version 2.21.0.fuse-720050-redhat-00001

[user@localhost somescripts]$ ./gradlew bootRun
> Task :bootRun
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.16.RELEASE)
...
2019-05-07 13:44:01.968 INFO 7497 --- [ main] o.a.camel.spring.SpringCamelContext : Apache Camel 2.21.0.fuse-720050-redhat-00001 (CamelContext: camel-1) started in 0.300 seconds
2019-05-07 13:44:01.985 INFO 7497 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2019-05-07 13:44:01.989 INFO 7497 --- [ main] c.c.somescripts.SomescriptsApplication : Started SomescriptsApplication in 4.702 seconds (JVM running for 5.19)
2019-05-07 13:44:02.981 INFO 7497 --- [- timer://hello] route3 : hello world timer fired 1
2019-05-07 13:44:07.968 INFO 7497 --- [- timer://hello] route3 : hello world timer fired 2
2019-05-07 13:44:12.968 INFO 7497 --- [- timer://hello] route3 : hello world timer fired 3
<==========---> 80% EXECUTING [22s]
> :bootRun

And we can confirm that the project is using the Red Hat Fuse dependencies by running ./gradlew dependencies

[user@localhost somescripts]$ ./gradlew dependencies
> Task :dependencies
------------------------------------------------------------
Root project
------------------------------------------------------------
<<< REDACTED >>>
compileClasspath - Compile classpath for source set 'main'.
+--- org.springframework.boot:spring-boot-starter -> 1.5.16.RELEASE
| +--- org.springframework.boot:spring-boot:1.5.16.RELEASE
<<< REDACTED >>>
+--- org.apache.camel:camel-core -> 2.21.0.fuse-720050-redhat-00001
| +--- org.slf4j:slf4j-api:1.7.22.redhat-2
| +--- com.sun.xml.bind:jaxb-core:2.2.11.redhat-4
| \--- com.sun.xml.bind:jaxb-impl:2.2.11.redhat-4
+--- org.apache.camel:camel-servlet -> 2.21.0.fuse-720050-redhat-00001
| +--- org.apache.camel:camel-core:2.21.0.fuse-720050-redhat-00001 (*)
| \--- org.apache.camel:camel-http-common:2.21.0.fuse-720050-redhat-00001
| \--- org.apache.camel:camel-core:2.21.0.fuse-720050-redhat-00001 (*)
+--- org.apache.camel:camel-jackson -> 2.21.0.fuse-720050-redhat-00001
| +--- org.apache.camel:camel-core:2.21.0.fuse-720050-redhat-00001 (*)
| +--- com.fasterxml.jackson.core:jackson-databind:2.8.11.1 -> 2.8.11.2 (*)
| \--- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.8.11
| +--- com.fasterxml.jackson.core:jackson-core:2.8.11
| +--- com.fasterxml.jackson.core:jackson-annotations:2.8.0
| \--- com.fasterxml.jackson.core:jackson-databind:2.8.11 -> 2.8.11.2 (*)
\--- org.apache.camel:camel-spring-boot-starter -> 2.21.0.fuse-720050-redhat-00001
+--- org.springframework.boot:spring-boot-starter:1.5.10.RELEASE -> 1.5.16.RELEASE (*)
+--- org.apache.camel:camel-spring-boot:2.21.0.fuse-720050-redhat-00001
| \--- org.apache.camel:camel-spring:2.21.0.fuse-720050-redhat-00001
| +--- org.apache.camel:camel-core:2.21.0.fuse-720050-redhat-00001 (*)
| +--- org.springframework:spring-core:4.3.17.RELEASE -> 4.3.19.RELEASE
| +--- org.springframework:spring-aop:4.3.17.RELEASE -> 4.3.19.RELEASE (*)
<<< REDACTED >>>
view raw gradle-deps.txt hosted with ❤ by GitHub

In order to create a fat spring-boot jar we run ./gradlew bootjar

[user@localhost somescripts]$ ./gradlew bootjar
BUILD SUCCESSFUL in 2s
3 actionable tasks: 3 executed

We can now see that a build has been generated with a somescripts-0.0.1-SNAPSHOT.jar

[user@localhost somescripts]$ tree
.
├── build
│ ├── classes
│ │ └── groovy
│ │ └── main
│ │ └── com
│ │ └── codergists
│ │ └── somescripts
│ │ ├── SomescriptsApplication$1.class
│ │ └── SomescriptsApplication.class
│ ├── generated
│ │ └── sources
│ │ └── annotationProcessor
│ │ └── groovy
│ │ └── main
│ ├── libs
│ │ └── somescripts-0.0.1-SNAPSHOT.jar
│ ├── resources
│ │ └── main
│ │ └── application.properties
│ └── tmp
│ ├── bootJar
│ │ └── MANIFEST.MF
│ └── compileGroovy
│ └── groovy-java-stubs
[user@localhost somescripts]$ ls -lah ./build/libs/somescripts-0.0.1-SNAPSHOT.jar
-rw-rw-r--. 1 user user 26M May 7 13:56 ./build/libs/somescripts-0.0.1-SNAPSHOT.jar
view raw fat-jar-ls.txt hosted with ❤ by GitHub

This jar is now portable and should run anywhere with java 8 by running java -jar ${jarfile} as below:

[user@localhost somescripts]$ java -jar ./build/libs/somescripts-0.0.1-SNAPSHOT.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.16.RELEASE)
2019-05-07 14:07:55.860 INFO 8842 --- [ main] c.c.somescripts.SomescriptsApplication : Starting SomescriptsApplication
<< REDACTED >>
view raw run-fat-jar.txt hosted with ❤ by GitHub

You should also be able to confirm that the REST service is available with curl

[user@localhost somescripts]$ curl localhost:8080/camel/hello
{"hello":"world"}
view raw curl-camel.txt hosted with ❤ by GitHub

Asciinema

References


codergists