Jrebel not reloading JSON file in resources - java

I'm working on a Spring Multi Module Project.
One of the projects contains some JSON file in a folder called drivers, located
in: <Project>/src/main/resources.
When I first launch the app all the JSON files are correctly loaded, but if I make a change to one of them JRebel keeps on using the old one.
Is there a way to configure it to solve this issue?
Thank you.
Here is the rebel.xml for this project:
<?xml version="1.0" encoding="UTF-8"?>
<application generated-by="intellij" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_1.xsd">
<classpath>
<dir name="C:/PathToProject/target/classes">
</dir>
<dir name="C:/PathToProject/src/main/resources/drivers">
</dir>
</classpath>
<web>
<link target="/">
<dir name="C:/PathToProject/src/main/webapp">
</dir>
</link>
</web>
</application>

Change the classpath part to
<classpath>
<dir name="C:/PathToProject/src/main/resources/"/>
<dir name="C:/PathToProject/target/classes"/>
</classpath>
If the application is trying to load a classpath resource, its full name is important(e.g. drivers/myfile.json) as this is what is passed to the classloader. The rebel.xml must specify paths that are classpath roots, not subfolders. For finer control you can use includes/excludes for the dir entry.
Also the paths are checked in order and if it exists in the first one, that is returned even if it's older.
So in your current configuration JRebel would first search for
C:/PathToProject/target/classes/drivers/myfile.json and find the old version there from the last run of maven-resources-plugin copy-resources goal or project build in IDE.
Now if only the order was fixed, the second path is still incorrect as it would look for C:/PathToProject/src/main/resources/drivers/drivers/myfile.json where it doesn't exist.

Related

JRebel will not hot deploy source files with embedded tomcat in intellij

I have the following project structure
project-root
--core
---build.gradle
---project.gradle
--web
---build.gradle
---project.gradle
I configured jRebel to run with gradle, so I can start my embedded tomcat 8 with the command gradle tomcatRun
This shows log-output of jrebel and my application starts on the embedded server, but there is no hot deployment when i change java files.
With the IntelliJ JRebel Plugin I created the rebel.xml files for each of the project project-root, core and web. Also I added a rebel.xml inside the web project in the folder web/build/classes/main as described here
Normally jrebel should show at startup that its wachting some folders, but this is not the case on my site, so i guess there is something wrong with my configuration
here the rebel.xml files
project-root (Path c:/project-root/rebel.xml)
<?xml xsd....">
<classpath>
<dir name="c:/project-root/out/production/classes">
</dir>
</classpath>
</application>
core (Path c:/project-root/core/src/main/resources/rebel.xml)
<?xml version="1.0" encoding="UTF-8"?>
<application generated-by="intellij" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_1.xsd">
<classpath>
<dir name="c:/project-root/core/out/production/resources">
</dir>
<dir name="c:/project-root/core/out/production/classes">
</dir>
</classpath>
</application>
web (Path c:/project-root/web/src/main/resources/rebel.xml)
<?xml version="1.0" encoding="UTF-8"?>
<application generated-by="intellij" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_1.xsd">
<classpath>
<dir name="c:/project-root/web/out/production/classes">
</dir>
</classpath>
</application>
web (Path c:/project-root/web/build/classes/main/rebel.xml)
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com"
xsi:schemaLocation="http://www.zeroturnaround.com http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd">
<classpath>
<dir name="c:/project-root/web/build/classes/main">
</dir>
</classpath>
<web>
<link target="/">
<dir name="c:/project-root/web/src/main/webapp">
</dir>
</link>
</web>
</application>
To attach jrebel to my gradle i did the following batch calls before starting gradle tomcatRun
set REBEL_HOME=C:\Users\myuser\.IdeaIC2017.3\config\plugins\jr-ide-idea\lib\jrebel6
set JAVA_OPTS="-agentpath:%REBEL_HOME%\lib\jrebel64.dll"
then calling gradlew tomcatRun starts the tomcat and jrebel
gradlew tomcatRun
2018-01-09 10:24:09 JRebel: Starting logging to file: C:\Users\myuser\.jrebel\jrebel.log
2018-01-09 10:24:09 JRebel:
2018-01-09 10:24:09 JRebel: #############################################################
2018-01-09 10:24:09 JRebel:
2018-01-09 10:24:09 JRebel: JRebel Agent 7.1.3 (201711301108)
2018-01-09 10:24:09 JRebel: (c) Copyright ZeroTurnaround AS, Estonia, Tartu.
2018-01-09 10:24:09 JRebel:
2018-01-09 10:24:09 JRebel: Over the last 2 days JRebel prevented
2018-01-09 10:24:09 JRebel: at least 0 redeploys/restarts saving you about 0 hours.
But when I change some source files, nothing is detected by jrebel, also when i manually called gradlew compileJava
I think that the problem is that JRebel is not attached to the actual process running the embedded Tomcat server. Instead, it gets attached to the Gradle's wrapper process. Try attaching JRebel's JVM argument via the org.gradle.jvmargs option instead.
gradle tomcatRun -Dorg.gradle.jvmargs="-agentpath:/path/to/jrebel/lib/libjrebel64.so"
Additionally, since tomcatRun task makes use of exploded deployment, rebel.xml files will not be necessary. This is because the build output directory is the same as the deployment directory and the changes made in that directory are automatically picked up by JRebel and reloaded.
Make sure to also compile the changes that you made using the gradle compileJava command to do so.
I tried it out personally and it seems to work well. Although it does not output the JRebel banner to the console output, it does let you know when a class file was reloaded.
While the answer by Tiit is correct, I would like to add that when using Gretty, you need to specify the -agentpath:/path/to/jrebel/lib/libjrebel64.so argument in your build.gradle file like so:
gretty {
. . .
jvmArgs = [
'-agentpath:/path/to/jrebel/lib/libjrebel64.so'
]
}
otherwise, by using -Dorg.gradle.jvmargs option, JRebel agent seems to attach to a wrong process when using Gretty launcher.

JRebel do not detect web resource changes over multiple webapp folders

I have a modular web project and thus I am allowing modules to be a war archive including webapp folder. Using the following rebel.xml works fine on detecting class changes over all modules. But for some reason jrebel does not move when a html or js is changed.
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com"
xsi:schemaLocation="http://www.zeroturnaround.com http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd">
<classpath>
<!-- appserver -->
<dir name="/home/xx/data/appserver/target/classes/main"/>
<dir name="/home/xx/data/appserver/target/resources/main"/>
<!-- module -->
<dir name="/home/xx/data/as.module.core/target/classes/main"/>
<dir name="/home/xx/data/as.module.core/target/resources/main"/>
<dir name="/home/xx/data/as.module.mqlcore/target/classes/main"/>
<dir name="/home/xx/data/as.module.mqlcore/target/resources/main"/>
</classpath>
<!-- web>
<link target="/">
<dir name="/home/xx/data/appserver/src/main/webapp"/>
<dir name="/home/xx/data/as.module.core/src/main/webapp"/>
<dir name="/home/xx/data/as.module.mqlcore/src/main/webapp"/>
</link>
</web -->
<web>
<link target="/">
<dirset dir="/home/xx/data">
<include name="**/src/main/webapp"/>
</dirset>
</link>
</web>
</application>
EDIT:
Interesting fact is. When I use the commented part of web configuration all three webapp folders are in the log and will be monitored for changes. But the application server can not find all of the webapp files. When I use the second <web> configuration all files are seen by the application server but are not observed by jrebel. I think it is not possible to have multiple directories linked to "/"
Each of the modules eg .war or .jar files need to have their own rebel.xml files. Otherwise all of them will reload same resources and when having different classloaders all kind of weird things can happen.
It is possible to check which instance of the file JRebel actually uses by searching "found resource" from jrebel.log. It should be written something like this
sun.misc.Launcher$AppClassLoader#184be29 found resource: 'cfg/log4j.xml' from 'file:/C:/Projects/testproject/Trunk/edm/target/cfg/log4j.xml'.
It is also seen which of the file changed by loking up lines with Event like this:
[IntelliJFSNotify] Event 'CHANGE' on: 'C:/Projects/testproject/Trunk/edm/target/cfg/log4j.xml'
Usually found resource and changed file paths do not match if the file is not reloaded. If they do match then it is recommended to send absolute path of the file and jrebel.log to support#zeroturnaround.com for investigation.
Ok, the answer is: indeed it is not possible to configure more than one directory under the <web><link target="/"></link></web> configuration. I have now a folder ./target/all-webapp where I smylink (cp -sR) all files via gradle task ... not nice but works ... and thank god jrebel is following symlinks!

Error with self-bootstrapping Ant build

I'm trying to write an Ant build that does not require me adding Ant-plugins to Ant's lib directory, or /home/myuser/.ant/lib, or in my Eclipse instance's ant home, etc; namely because I will eventually be building my project on a hosted Jenkins server where I do not have access to the system's Ant installation.
I'm calling this a "self-bootstrapping" build, because I use Ivy to pull down my Ant plugins at build time, and hopefully, with some proper configuration, make their tasks available to Ant dynamically.
The jist of my build (using ant-contrib plugin as an example:
<?xml version="1.0" encoding="utf-8" ?>
<project name="myapp" default="audit" basedir="."
xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:antcontrib="antlib:net.sf.antcontrib">
<!-- Build path. -->
<path id="build.path">
<fileset dir="${lib.buildtime.dir}" includes="**/*.jar"/>
</path>
<target name="bootstrap">
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant" classpathref="build.path"/>
</target>
<target name="resolve" depends="bootstrap">
<ivy:settings url="${ivy.settings.home}"/>
<ivy:cleancache/>
<ivy:resolve file="${ivy.xml}"/>
<ivy:retrieve pattern="${gen.lib.main.dir}/[artifact]-[revision].[ext]" conf="main"/>
<ivy:retrieve pattern="${gen.lib.test.dir}/[artifact]-[revision].[ext]" conf="test"/>
<ivy:retrieve pattern="${gen.lib.buildtime.dir}/[artifact]-[revision].[ext]" conf="buildtime"/>
<ivy:report todir="${gen.staging.dir}" />
<ivy:cachepath pathid="build.path" conf="buildtime"/>
</target>
<target name="taskdefs" depends="resolve">
<taskdef resource="/net/sf/antcontrib/antlib.xml"
uri="antlib:net.sf.antcontrib" classpathref="build.path"/>
<property name="fizz" value="buzz" />
<antcontrib:if>
<antcontrib:equals arg1="${fizz}" arg2="buzz" />
<antcontrib:then>
<echo message="Fizz is buzz!" />
</antcontrib:then>
<antcontrib:else>
<echo message="Fizz is not buzz!" />
</antcontrib:else>
</antcontrib:if>
</target>
</project>
When I run the taskdefs target, instead of seeing an echoed "Fizz is buzz!" message in my Ant output, I get the following error:
BUILD FAILED
/home/myuser/eclipse/workspace/myapp/build.xml:169: Problem: failed to create task or type antlib:net.sf.antcontrib:if
Cause: The name is undefined.
Action: Check the spelling.
Action: Check that any custom tasks/types have been declared.
Action: Check that any <presetdef>/<macrodef> declarations have taken place.
No types or tasks have been defined in this namespace yet
This appears to be an antlib declaration.
Action: Check that the implementing library exists in one of:
-/home/myuser/eclipse/plugins/org.apache.ant_1.8.3.v201301120609/lib
-/home/myuser/.ant/lib
-a directory added on the command line with the -lib argument
Is what I am trying to do (avoid having to do 1 of the 3 recommended things above) impossible? If so, why? If not, what is wrong with my setup here? Thanks in advance!
I normally create a single "boostrap" target and use this to install ivy into the "$HOME/.ant/lib" directory. See:
Ivy fails to resolve a dependency, unable to find cause
The following is a more complete example that does what you're trying to do:
How to include ant-contrib.jar dynamically in Ant
In conclusion, it's a shame ivy is not packaged by default with ANT. If you discover your hosted service prevents you from copying files into the home directory, then perhaps the simplest thing to do is ship a copy of the ivy jar alongside your source (and enable it using a taskdef)
Update
Use the following taskdef for ant-contrib:
<taskdef uri="antlib:net.sf.antcontrib" classpathref="build.path"/>
The homepage needs update. At some stage in the recent past the library was repackaged as an antlib.

How can I build an EAR file from a Dynamic Web Project in Eclipse?

I'm looking at deploying a web service which I've written in Eclipse to an EAR file. I'm able to export it as a WAR and deploy it on Tomcat all fine and dandy, but the final product won't be on Tomcat, and won't be a WAR file. I'll need to use Websphere as a server, which I have access to and can deploy valid EAR files... if I had an EAR file to deploy.
So long story short, how do I export an EAR file from a Dynamic Web Project in Eclipse?
You need to create an Enterprise Application Project (basically, an EAR) in Eclipse, add the Dynamic Web Project to the EAR project, and then export the whole thing.
for this I use an Ant build script, (you can create a new Ant file in Eclipse, store it in your dynamic web project root and then right click > run on it when you want to run it from eclipse. Something like below. Basically copy your war to a directory, ${earDir} in the script below, and build that to an EAR (an EAR is just a type of JAR) :
<target name="buildEar" depends="init">
<copy tofile="${earDir}/" file="yourWarFile"/>
<copy tofile="${earDir}/META-INF/application.xml" file="localDirectory/application.xml"/>
<copy todir="${earDir}/META-INF">
<fileset dir="localDirectory" includes="was.policy" />
</copy>
<jar jarfile="localDir/something.ear" basedir="${earDir}">
<!-- Define the properties for the Manifest file. -->
<manifest>
<attribute name="Implementation-Vendor" value="Company name"/>
<attribute name="Implementation-Title" value="Application Title"/>
<attribute name="Implementation-Version" value="version and build number"/>
</manifest>
</jar>
</target>
Your was.policy file will be something like this (not good to give all permissions but you can change it later once you have it up and running):
//
// Template policy file for enterprise application.
// Extra permissions can be added if required by the enterprise application.
//
// NOTE: Syntax errors in the policy files will cause the enterprise application FAIL to start.
// Extreme care should be taken when editing these policy files. It is advised to use
// the policytool provided by the JDK for editing the policy files
// (WAS_HOME/java/jre/bin/policytool).
//
grant codeBase "file:${jars}" {
};
grant codeBase "file:${connectorComponent}" {
};
grant codeBase "file:${webComponent}" {
};
grant codeBase "file:${ejbComponent}" {
};
grant codeBase "file:${application}" {
permission java.security.AllPermission;
};
Your application.xml file will be something like this:
<?xml version="1.0" encoding="UTF-8"?>
<application id="Application_ID" version="1.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/application_1_4.xsd">
<display-name>yourAppName</display-name>
<module id="WebModule_1240219352859">
<web>
<web-uri>yourWarFile.war</web-uri>
<context-root>urlToApplication</context-root>
</web>
</module>
</application>
The ids there should be ok they need to be unique per EAR I believe (or is it server cant remember).
I hope this helps.

Beanshell in Ant yielding, "Unable to create javax script engine for beanshell"

Greeting, I'm trying to put some Beanshell script in my Ant build.xml file. I've followed the Ant manual as well as I can but I keep getting "Unable to create javax script engine for beanshell" when I run Ant. Here is the test target I wrote mostly from examples in the Ant manual:
<target name="test-target">
<script language="beanshell" setbeans="true">
<classpath>
<fileset dir="c:\TEMP" includes="*.jar" />
</classpath>
System.out.println("Hello world");
</script>
</target>
My beanshell "bsh-2.0b4.jar" file is on the script task's classpath the way the manual recommended. Hope I have the right file. I'm working in c:\TEMP right now.
I've been googling and trying for a while now. Any ideas would be greatly appreciated. Thanks.
First, you need jsr-engines.zip from here:
https://scripting.dev.java.net/servlets/ProjectDocumentList
Inside, you'll find jsr223/beanshell/build/bsh-engine.jar. Some searching implied that you need to download bsh-2.05b.jar. I found it here:
http://beanshell.org/bsh-2.0b5.jar
The more easily findable bsh-2.0b4.jar also seemed to work, but it printed a message that implied it was experimental.
Currently (2012) you need only 1 jar to fire the script task for BeanShell:
bsh-2.0b5.jar
Previously I also thought of the following, as mentioned by Ant Manual, Library Dependencies chapter:
bsf-2.4.0.jar
commons-logging-api-1.1.jar
But it looks like bsf is not needed for bsh, at least in my environment.
Once the jar is given to ant, the script task runs smoothly. There are 2 possible scenarios for getting the jars and making them available to ant.
Manual download way
Download the jars above. I provided the links from maven repository. Once you have all the jars downloaded, make them available to ant. There are
at least 3 ways to do it:
Put it in java library path
Put it in ant library directory
Give the correct classpath to script task.
I find the last method the best, because it is most easily ported between
different systems. The ant file for the script task could look as follows:
<project default="t1" >
<property name="bsh.path"
location="/mnt/q/jarek/lang/java/ant/stackoverflow/bsh-2.0b5.jar" />
<target name="t1">
<script language="beanshell" classpath="${bsh.path}">
javax.swing.JOptionPane.showMessageDialog(null, "Hello, Script!");
</script>
</target>
</project>
Automatic download method, employing Ivy
The manual method is not perfect when you want to distribute your build script. Then you would like a way to make sure the jars are present in the destination system. For distributing builds there's no better tool than ivy. Ivy will download the jars and put them in classpath for you. The problem is that there appears another dependency, which is ivy itself. But providing ivy.jar is quite easy and that is the last dependency we need to supply explicitly.
One may ask why to provide ivy.jar, while we could simply download bsh.jar in the same way. The answer is flexibility. When you have the ivy.jar, you get any jar you wish with a single step being adding it to the ivy.xml file. And there is an agreed universal location for the ivy.jar file, while for other file we would have to think of a suitable directory.
Below comes the full example that downloads ivy and then all the necessary dependencies. Ivy download script is based on Installation chapter of Ivy reference.
Then a simple ivy.xml file is needed, which is given after the sample build.xml.
Original auto-download ivy script has a disadvantage of always checking the ivy url, even if ivy.jar is already in the expected location. This may be overriden by specifying -Doffline=true. I prefer to add another target to the build file and to do the http check only if we don't already have the ivy.jar. This is the way the script here works. To observe what ivy actually downloaded, set IVY_HOME environment variable to a directory of your choice. It will be created and filled with ivy stuff.
build.xml:
<project default="t1"
xmlns:ivy="antlib:org.apache.ivy.ant" >
<property name="ivy.install.version" value="2.2.0" />
<property environment="env" />
<condition property="ivy.home" value="${env.IVY_HOME}">
<isset property="env.IVY_HOME" />
</condition>
<property name="ivy.home" value="${user.home}/.ant" />
<property name="ivy.jar.dir" value="${ivy.home}/lib" />
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />
<target name="check-ivy">
<condition property="ivy.present">
<available file="${ivy.jar.file}" type="file" />
</condition>
</target>
<target name="download-ivy" unless="ivy.present">
<mkdir dir="${ivy.jar.dir}"/>
<!-- download Ivy from web site so that it can be used even without any special installation -->
<get src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
dest="${ivy.jar.file}" usetimestamp="true"/>
</target>
<target name="init-ivy" depends="check-ivy, download-ivy">
<!-- try to load ivy here from ivy home, in case the user has not already dropped
it into ant's lib dir (note that the latter copy will always take precedence).
We will not fail as long as local lib dir exists (it may be empty) and
ivy is in at least one of ant's lib dir or the local lib dir. -->
<path id="ivy.lib.path">
<fileset dir="${ivy.jar.dir}" includes="*.jar"/>
</path>
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
</target>
<target name="ivy-libs" depends="init-ivy" >
<ivy:cachepath pathid="path.from.ivy" log="download-only" />
</target>
<target name="t1" depends="ivy-libs" >
<script language="beanshell" classpathref="path.from.ivy">
javax.swing.JOptionPane.showMessageDialog(null, "Hello, Script!");
</script>
</target>
</project>
ivy.xml:
<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation=
"http://ant.apache.org/ivy/schemas/ivy.xsd">
<info organisation="example.com" module="testing-script-task" />
<dependencies>
<dependency org="org.beanshell" name="bsh" rev="2.0b5" />
<!-- <dependency org="bsf" name="bsf" rev="2.4.0" /> -->
</dependencies>
</ivy-module>
The Ant plug-in "org.apache.ant_1.7.0.v200803061910" have all the jar files needed
Don't use beanshell language. Use javascript instead, as it runs on jdk6 without any additional jars. Rebse told me that.
Javascript is also allowed to use java classes, for example java.lang.System.out.println()

Categories