I am learning Spring MVC and trying to use it together with Gradle and Gretty plugin. I have successfully created a "Hello World" project, however I am not able to use hot deployment with Gretty, despite setting the managedClassReload=true. I run the application by using appRun gretty task from IntelliJ. My build.gradle is as follows:
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'war'
apply from: 'https://raw.github.com/gretty-gradle-plugin/gretty/master/pluginScripts/gretty.plugin'
group = 'lukeg'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
mainClassName = 'lukeg.LearnApplication'
repositories {
mavenCentral()
maven {
url 'https://repo.spring.io/libs-snapshot'
}
}
dependencies {
compileOnly('org.projectlombok:lombok:+')
compile('org.springframework:spring-webmvc:4.3.17.RELEASE')
compile("org.aspectj:aspectjweaver:1.8.11")
compile('org.springframework:spring-context:4.3.18.BUILD-SNAPSHOT')
providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
}
gretty {
httpPort = 8080
contextPath = '/'
servletContainer = 'tomcat9'
//reloadOnClassChange=true
managedClassReload=true
loggingLevel='DEBUG'
}
It does not matter whether I use tomcat9 or jetty9 for servlet container: the logs do not show that the changes to source files in project are detected by Gretty.
Interesingly enough, when I comment out the managedClassReload=true line and uncomment reloadOnClassChange=true the changes to source files are detected and the project is automatically reloaded.
What can be the cause for gretty's hot deployment not working? Does springloaded not work together with Spring MVC?
First of all, there is no need to depend on the plugin script you are gathering from github since org.gretty is available in the official Gradle plugin repository for some time already:
plugins {
id "org.gretty" version "2.1.0"
}
Since you are running your app inplace using appRun, your changes will not be reloaded.
You have to run you application as war, using appRunWar.
This is not mentioned in the documentation. But in the Gretty source code.
You can check the Gretty code which causing your issue in the BaseScannerManager:
if(wconfig.reloadOnClassChange)
{
if(managedClassReload)
{
if(wconfig.inplace) // <-- your problem, you are running inplace
{
log.info 'file {} is in managed output of {}, servlet-container will not be restarted', f, wconfig.projectPath
}
else
{
log.info 'file {} is in output of {}, but it runs as WAR, servlet-container will be restarted', f, wconfig.projectPath
webAppConfigsToRestart.add(wconfig)
}
}
else
{
log.info 'file {} is in output of {}, servlet-container will be restarted', f, wconfig.projectPath
webAppConfigsToRestart.add(wconfig)
}
}
Related
Config: Eclipse Neon.1. BuildShip plugin 1.0.21. Gradle 3.2. Tomcat 8.0.33.
Project Structure:
CmbProduct
Common
CommonServer
Model
CaBridge
WebApp
I've got a Web Services application project ("WebApp") which is dependent on multiple other projects. When I use Eclipse WST/WTP to deploy and run WebApp via Tomcat, only Model.jar from "Model" is deployed into the tomcat WST runtime directory as:
.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapp/WEB-INF/lib/Model.jar
All other dependencies for hibernate, etc do seem to be deployed correctly to the same dir above.
This broke when I changed eclipse to use Buildship. Previously I used the Eclipse STS (Spring) plugin and that worked fine.
Here is the web project (WebApp) build.gradle:
apply plugin: 'war'
apply plugin: 'eclipse-wtp'
dependencies {
compile project(":Common")
compile project(":Model")
compile project(":CommonServer")
compile project(":CaBridge")
...
}
eclipse {
wtp {
component {
// Configure the <Context path="..."/> in server.xml
contextPath = '/console'
// dependencies to mark as deployable with lib folder deploy path
libConfigurations += [ project(":MagniCompCommon").configurations.runtime ]
}
}
}
In the above example I first tried without the eclipse.wtp.libConfigurations section. I tried adding that to fix the problem but it has no effect. Yes, I did run 'gradle eclipseWtp', then Add/Remove the 'WebApp' application from its server entry after making that change.
If I go to Eclipse -> WebApp -> Properties -> Java Build Path -> Libraries and look at "Web App Libraries" I see "Model" but not the other projects. If I look at "Project and External Dependencies" I see all projects listed.
Here is the build.gradle for Model (working):
apply plugin: 'eclipse-wtp'
dependencies {
compile project(":MagniCompCommon")
}
Here is build.gradle for Common (not deployed):
apply plugin: 'eclipse-wtp'
dependencies {
//compile project(":MagniCompCommon")
compile project(":Model")
compile("org.glassfish.jersey.containers:jersey-container-servlet:$jerseyGlassfishVersion")
// Required for JAX-RS Client
compile("org.glassfish.jersey.core:jersey-client:$jerseyGlassfishVersion")
}
Here is build.gradle for the top level project (CmbProject):
apply plugin: 'java'
subprojects {
apply plugin: 'java'
apply plugin: 'nebula.provided-base'
apply plugin: 'nebula.optional-base'
sourceCompatibility = JavaVersion.VERSION_1_8
javadoc.enabled = false
sourceSets {
main {
java {
// Define all source dirs - Purpose is to add "src-gen"
srcDirs = ["src/main/java", "src-gen"]
}
}
}
/*
* Repositories used by each subproject must be given below.
* Because each subproject resolves dependencies of other
* subprojects, all subprojects must know all repos.
* In other words, if projectA needs repo "foo.org" and projectB
* depends upon projectA, then projectB needs repo "foo.org" as
* well.
*/
repositories {
maven {
// Local repo for annovention
url uri("$rootDir/MagniCompCommon/repo")
}
mavenCentral()
maven {
url "http://download.java.net/maven/2"
}
maven {
// Texo/EMF
url "https://oss.sonatype.org/content/groups/public/org/eclipse/emf"
}
maven {
// Eclipse
url "https://oss.sonatype.org/content/repositories/public/eclipse"
}
maven {
url "https://repository.jboss.org/nexus/content/groups/public-jboss"
}
maven {
url "http://maven.vaadin.com/vaadin-addons"
}
maven {
url "http://oss.sonatype.org/content/repositories/vaadin-snapshots"
}
maven {
url("http://maven.clapper.org")
}
/*
* -ADD LAST- so that it doesn' override any others
* DynamicReports depends upon JasperReports which lists their own
* bug fixed versions of packages like "com.lowagie:itext:2.1.7.js2"
* This repo provides such patched packages.
*/
maven {
url("http://jasperreports.sourceforge.net/maven2")
}
}
/*
* Variables local to this file
*/
def bouncycastleVersion = "1.54" // Was 1.51
def slf4jVersion = "1.7.19"
def hibernateVersion = "4.3.11.Final"
def texoVersion = "0.9.0-v201501182340"
def emfVersion = "2.11.0-v20150123-0347"
def jnaVersion = "4.1.0"
ext {
/*
* Variables here are used by subprojects
*/
vaadinVersion = "7.6.8" // was 7.6.4
vaadinIconsVersion = "1.0.1"
jerseyGlassfishVersion = "2.23.2" // was 2.22.2
}
dependencies {
/*
* PRODUCT SPECIFIC
*/
compile("org.bouncycastle:bcprov-jdk15on:$bouncycastleVersion")
compile("org.bouncycastle:bcprov-ext-jdk15on:$bouncycastleVersion")
compile("org.bouncycastle:bcpkix-jdk15on:$bouncycastleVersion")
compile("com.h2database:h2:1.3.176")
testCompile("org.testng:testng:6.9.4")
/*
* MagniComp common and product
*/
compile("org.simpleframework:simple-xml:2.6.9")
// Logging slf4j API
compile("org.slf4j:slf4j-api:$slf4jVersion")
// Send JCL to slf4j
compile("org.slf4j:jcl-over-slf4j:$slf4jVersion")
// Anything using JUL should defer to slf4j
compile("org.slf4j:jul-to-slf4j:$slf4jVersion")
// Send slf4j to log4j 1.2 for those JARs which use slf4j
compile("org.slf4j:slf4j-log4j12:$slf4jVersion")
// Log4j itself
compile("log4j:log4j:1.2.17")
// Hibernate
// Do not include "hibernate-core" explicitly as hibernate-entitymanager will take care of it
compile("org.hibernate:hibernate-entitymanager:$hibernateVersion")
compile("org.hibernate:hibernate-c3p0:$hibernateVersion")
compile("mysql:mysql-connector-java:5.1.38")
// Texo
compile("org.eclipse.emf:org.eclipse.emf.texo:$texoVersion")
compile("org.eclipse.emf:org.eclipse.emf.texo.server:$texoVersion")
compile("org.eclipse.emf:org.eclipse.emf.texo.xml:$texoVersion")
// Texo dependencies (not automaticly added by texo)
compile("org.eclipse.emf:org.eclipse.emf.common:$emfVersion")
compile("org.eclipse.emf:org.eclipse.emf.ecore:$emfVersion")
compile("org.eclipse.emf:org.eclipse.emf.ecore.xmi:$emfVersion")
// Required by org.eclipse.emf
// Disable because it's causing:
// java.lang.SecurityException: class "org.osgi.framework.BundleReference"'s signer information does not match signer information of other classes in the same package
//compile("org.eclipse.core:org.eclipse.core.runtime:3.7.0")
compile("org.jsoup:jsoup:1.7.2")
// Apache HTTP client
compile("org.apache.httpcomponents:httpclient:4.3.5")
// EventBus and more
compile("com.google.guava:guava:18.0")
// Quartz scheduler
compile("org.quartz-scheduler:quartz:2.2.2") {
exclude group: "c3p0", module: "c3p0"
}
// Java Mail
compile("javax.mail:mail:1.4.5")
// JNA for Common and CaBridge
compile("net.java.dev.jna:jna:$jnaVersion")
compile("net.java.dev.jna:jna-platform:$jnaVersion")
// This package provided by Tomcat or Servlet container
provided("javax.servlet:javax.servlet-api:3.1.0")
}
}
Thanks to some help from the gradle forum I found the solution.
Each project which is a dependency of a WTP project must each have:
apply plugin: 'eclipse-wtp'
Having this only in the WTP project is not enough.
HELP!
I'm using the built-in launch script with SpringBoot 1.3.6 and Gradle. Oh, and the distZip task to zip things up.
At one point not long ago, this was all working quite well... then I did -- I know not what -- to screw it up.
I've installed the package (unzipped the Zip, basically) on my raspberry Pi, and checked the ownership and permissions. Everything is owned by the user I want to run the app as (user "appservice" group "pi") and confirmed that the permissions for the files are -- if anything, too permissive (755 for the myapp/bin/myapp script and pretty much everything else).
I've put a symlink in /etc/init.d pointing to ~appservice/myapp/bin/myapp and I've run update-rc.d myapp defaults to get it into the system. Note the symlink itself is owned by root/root, but I believe it's supposed to be, isn't it?
I'm seeing two problems, that I think are interrelated.
First, no matter how I launch the script (on boot with init.d or manually with "sudo service myapp start"), it appears to run as root (specifically, paths that the app is trying to use to access files come out as /root/myapp/files instead of /home/appservice/myapp/files).
Second, the app will crash... specifically I get the syslog message "myapp.service start operation timed out. Terminating." followed by what looks like an orderly shutdown of the app. Oh, and related... if I launch with "sudo service myapp start" the command never returns. Which is new...
Third, the application log output is going to /var/log/syslog instead of to /var/log/myapp.log which seems counter to what the Spring Boot documentation says.
I'm in final regression testing of deployment for this, and (famous last words) I haven't changed anything recently... :) No, really, the most recent change relevant to distribution was adding the src/main/dist directory, and it was working after that (launching at boot as the correct user).
I'd post the launch script but AFAIK it's the default script provided by Spring Boot when you use the springBoot { executable = true } task.
Here's my full build.gradle file... I don't see anything amiss, but maybe you will.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.6.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'application'
apply from: 'gradle/gradle/helpers.gradle'
mainClassName = 'app.Application'
if (!hasProperty('mainClass')) {
ext.mainClass = 'app.Application'
}
springBoot {
executable = true
}
repositories {
mavenCentral()
}
sourceSets {
main {
java { srcDir 'src/main/java' }
resources { srcDir '/src/main/resources' }
}
test {
java { srcDir 'src/test/java' }
resources { srcDir 'src/test/resources' }
}
}
project.ext {
applicationVersion = "0.1.5-alpha"
applicationRelease = isApplicationRelease()
applicationDate = new Date()
applicationRevision = getRevision()
applicationVersionSnapshot = (!applicationRelease) ? "+SNAPSHOT.${asUTC(applicationDate, 'yyMMddHHmm')}.git${applicationRevision}" : ""
applicationVersionFull = "${applicationVersion}${applicationVersionSnapshot}"
}
jar {
baseName = 'myapp'
version = '0.9.0'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile group: 'com.sun.mail', name: 'javax.mail', version: '1.5.2'
compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3.6'
compile group: 'commons-cli', name:'commons-cli', version: '1.3.1'
compile group: 'org.json', name:'json', version: '20140107'
compile "commons-codec:commons-codec:1.10"
compile("org.springframework.boot:spring-boot-starter-hateoas")
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
compile("org.springframework.boot:spring-boot-starter-mail")
compile("org.springframework.boot:spring-boot-starter-security")
compile("org.springframework:spring-web")
compile("org.springframework:spring-messaging")
compile("joda-time:joda-time:2.2")
compile("com.fasterxml.jackson.core:jackson-databind")
compile("com.googlecode.json-simple:json-simple")
compile("org.jdom:jdom:2.0.0")
compile("org.hibernate:hibernate-validator")
compile("org.apache.tomcat.embed:tomcat-embed-el")
compile("org.apache.commons:commons-io:1.3.2")
compile("org.kamranzafar:jtar:2.3")
compile("org.thymeleaf.extras:thymeleaf-extras-springsecurity4")
compile("com.jcraft:jsch:0.1.53")
compile("javax.jmdns:jmdns:3.4.1")
testCompile("org.springframework.boot:spring-boot-starter-test")
}
task wrapper(type: Wrapper) {
gradleVersion = '2.14'
}
I would recommend to run and manage your application with systemd.
This makes it very easy to run the application under a specific user.
To do so, go on as follows:
First, create a service definition file /etc/systemd/system/myapp.service with this content:
[Unit]
Description=My App
[Service]
User=nobody
# The configuration file application.properties should be here:
WorkingDirectory=/home/appservice/myapp/files
ExecStart=/usr/bin/java -Xmx256m -jar myapp.jar
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
Then, notify systemd of the new service file:
systemctl daemon-reload
and enable it, so it runs on boot:
systemctl enable myapp.service
At the end you can use the following commands to start/stop your new service:
systemctl start myapp
systemctl stop myapp
I would like to use Gradle to build a java project and I would like to structure it as follows.
Core Library
Web App (war plugin)
Server (application plugin)
Client
Client War (war plugin)
The Web App, Server, and Client all depend on core. The Server depends on the Web App because it is going to serve it as the admin page using embedded Jetty. The Client War depends on the Client. The Client War is to be deployed to a web server for distribution of the client as a web start application.
What I would like to know is how can I tell the Server project that it depends on the Web App and needs to copy it into the proper location in it's distribution structure. I would also like to know how I can tell the Client War project to depend on the Client project and to copy the Client jar and all of it's dependencies into the proper location to build the war archive.
I plan to use the application plugin for the Server so under <root>/src/dist there will be a webapp directory where the one or possibly more web apps will reside. It is expected that the files contained in the webapp directory will be war files.
This is a new project so it can follow the standard build conventions of Gradle and the project layout expected by Gradle.
Ideally at some point the Client artifacts will be published to an internal Artifactory or Sonatype Nexus repository so that the Client War can be built with version support.
So far I have found the following resources.
Packaging JNLP Applications in a Web Archive
Generating Java Web Start files using Gradle
I believe I figured out the Web App dependency part of my problem. The Client War is a lost cause for now.
Server build.gradle
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'application'
targetCompatibility = 1.8
sourceCompatibility = 1.8
version = '0.0.1-SNAPSHOT'
group = 'com.s2d'
mainClassName = 'com.simonsoftwaredesign.example.echo.server.EchoServerApp'
repositories {
mavenCentral()
}
configurations {
webContainer
}
dependencies {
compile project(':echo-core')
compile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.7.v20160115'
compile group: 'org.eclipse.jetty', name: 'jetty-webapp', version: '9.3.7.v20160115'
webContainer project(path: ':echo-admin', configuration: 'warApp')
}
task copyWebApps(dependsOn: configurations.webContainer, type: Copy) {
from { configurations.webContainer.collect { it } }
// I don't like how this is hard coded
// but I am not sure how to fix it
into 'src/main/dist/webapp'
}
installDist.dependsOn copyWebApps
distZip.dependsOn copyWebApps
distTar.dependsOn copyWebApps
Web App build.gradle
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'war'
targetCompatibility = 1.8
sourceCompatibility = 1.8
version = '0.0.1-SNAPSHOT'
group = 'com.s2d'
configurations {
warApp
}
repositories {
mavenCentral()
}
dependencies {
providedCompile project(':echo-core')
providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
}
artifacts {
warApp war
}
Gradle projects depending on artifacts created by sibling projects
At this moment I have a build.gradle file that successfuly compiles and tests (using JUnit4) a very very simple java project.
My next step is to add JSF2 support (in order to have a web JSF2 application) to this build. The idea is to host the application in my local JBoss 7.1 container. Now things became a little fuzzy to me.
What I did was to add JSF2 support to my buid by adding some dependencies, so the dependencies block is like this now:
dependencies {
compile 'org.jboss.weld.se:weld-se-core:'+weldVersion
compile 'br.gov.frameworkdemoiselle:demoiselle-core:'+demoiselleVersion
compile 'br.gov.frameworkdemoiselle:demoiselle-jsf:'+demoiselleVersion
runtime 'javax.servlet:javax.servlet-api:3.1.0'
runtime 'javax.enterprise:cdi-api:1.0-SP1'
runtime 'org.jboss.weld.servlet:weld-servlet:'+weldVersion
runtime 'com.sun.faces:jsf-api:2.2.8-02'
runtime 'org.slf4j:slf4j-log4j12:1.7.7'
testCompile 'junit:junit:4.11'
testCompile 'org.jboss.arquillian.junit:arquillian-junit-container:'+arquillianVersion
testCompile 'br.gov.frameworkdemoiselle.component:demoiselle-junit:2.3.1'
}
First strange thing that I noticed is that after refreshing the project with Gradle (by using Gradle > Refresh All menu), JBoss is unable to see it. I noticed that (it seems) Gradle disabled the use of facets in the project. If I manually activate facets and set the runtime to JBoss 7.1, then I'll be able to add it to JBoss (but I would prefer not to have to do it manually anymore).
After adding it to JBoss I can run the server, and the log says the module corresponding to my web application was correctly loaded by JBoss, however when I type it's url in a browser, the server responds with HTTP status 404.
In src/main/webapp I have the simple index.html file (shown below), so what I expected was just to see it's content in the browser, but that does not happen.
<html>
<body>
<h1>Hello world!</h1>
</body>
</html>
What am I missing?
After some study I finally understood that things were much simpler. That I was missing to understand is that I was using the wrong Gradle plug-in. I had to replace eclipse plug-in by eclipse-wtp and then specify which facets and runtime I wanted to use in my application.
The final build.gradle file is below:
apply plugin: 'java'
apply plugin: 'eclipse-wtp' // The correct plug-in!
apply plugin: 'application'
apply plugin: 'war'
sourceCompatibility = 1.7
targetCompatibility = 1.7
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
def hibernateVersion = "4.3.7.Final"
def weldVersion = "1.1.27.Final"//"2.2.7.Final" Demoiselle 2.4.1 não é compatível com Weld 2
def demoiselleVersion = "2.4.1"
def arquillianVersion = "1.1.5.Final"
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
runtime 'javax.servlet:javax.servlet-api:3.1.0'
runtime 'javax.enterprise:cdi-api:1.0-SP1'
runtime 'org.jboss:jandex:1.2.2.Final'
}
eclipse {
wtp {
facet {
facet name: "java", version: "1.7" // Java version
facet name: "jst.web", version: "3.0" // Dynamic Web Application
facet name: "jst.jsf", version: "2.2" // Java Server Faces
facet name: "wst.jsdt.web", version: "1.0" // JavaScript
}
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.2.1'
}
I hope this may help some other people!
Im trying to create a web application using Gradle. The front end UI will be built with Angular.js and the backend should be Java. When I say backend, I mean a Java / Spring based API that will be queried using Ajax from Angular.js.
So basically what Im trying to do is to get any URL's that start with mysite.com/api/... should be routed to the src/com/veight/client files, or in other words to the Java backend. And then any other URLs such as mysite.com/login should be handled by the JavaScript / Angular.js front end.
I have the JavaScript / Angular.js routing working for the front end using the following build.gradle file. How should I go about sending routes that match mysite.com/api/... to the Java / Spring back end?
Thank you for the help!
Note: I know that Java Spring naturally does this routing where it sends certain routes mysite.com/home to one folder and other routes mysite.com/api/... are handled buy a xml file. But I think its possible to handle this in the build.gradle file. So I was hoping to prove / disprove that theory.
File Structure
.gradle
.settings
build
gradle
src
com
veight
client
WebContent
Heres my build.gradle:
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'org.gradle.api.plugins:gradle-tomcat-plugin:1.2.4' // Gradle Tomcat Plugin
classpath 'com.eriwen:gradle-css-plugin:1.11.1'
classpath 'com.eriwen:gradle-js-plugin:1.12.0'
}
}
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'tomcat'
apply plugin: 'eclipse-wtp'
apply plugin: 'js'
apply plugin: 'css'
sourceCompatibility = 1.7
version = '1.0'
task wrapper(type: Wrapper) {
gradleVersion = '2.0'
}
repositories {
mavenCentral() // Allow access to the Maven Centeral Repo
}
dependencies {
def tomcatVersion = '7.0.54'
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}"
tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}") {
exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj'
}
}
sourceSets {
main {
java {
srcDirs 'src'
}
}
}
// End: Java Plugin Configuration
// Start: Tomcat Plugin Configuration
tomcatRun {
httpPort = 8080
stopPort = 8081
URIEncoding = 'utf-8'
webAppSourceDirectory = file('WebContent')
}
eclipse {
wtp {
component {
contextPath = '/'
deployName = 'client'
}
}
}