SBT (Simple Build Tool): Change the build target "classes" directory - java

Question
For Java web applications, if you put classes where the web server expects them on your development machine, it can save you the step of packaging and redeploying your web-app every time you compile. It also simplifies things to have the development and deployment directory structure the same. Tomcat's Standard Directory Layout is:
WEB-INF/
WEB-INF/classes
WEB-INF/lib
But SBT wants to put all classes in:
target/scala-2.10/classes
How do I tell sbt to put classes in WEB-INF/classes instead?
Background
So far, I've been using SBT just for unit tests and I run it from WEB-INF instead of my project's root directory and don't worry about where it throws the classes because tests don't need to be deployed. I guess I could wrap SBT in a batch file that cd's to WEB-INF, then cd's back when done, but that seems a little kludgey.
How do people work around this issue? I could delete WEB-INF/classes then copy target/scala-2.10/classes to it after each build, but that might eliminate some of the benefits of incremental/minimal compilation that SBT offers.
Extra Credit...
I'm not sure if this is part of a new question, but it falls under "using SBT to build a Java web app" so I'll include it: Tools like log4j, Struts, proxool, and Hibernate all seem to expect files (and sub-directories recursively) to be copied from src/main/resources to classes on each build, and I could copy them explicitly the way I do with the Ant build now. But if SBT had a web-app-defaults, maven-defaults, or java-defaults template or something, that would be helpful to know about.

I think it should be
target := base / "WEB-INF"
or
classDirectory := base / "WEB-INF" / "classes"

Related

Resource file location in runnable jar

I have a maven project, that has resources files under dir src/main/resources. I noticed that in Eclipse, when I run the project, the source files are copied to target/classes without the resources directory, just the files under resources dir.
But after I exported the project to a runnable jar by using Right clieck on the project -> Jar -> Runnable Jar , these resource files are under resource directory:
As you see, the resource files are in diffrenent locations in two cases.
and below code works well in Eclipse, but not worked in runnable jars
getClassLoader().getResourceAsStream("database.properties")
How to solve this problem? I want the above code can work in both cases.
Answer is simple - do NOT trust Eclipse or any IDE for similar cases. Matters only separate build that will be running on the separate environment. The same also applies to the testing using embedded in IDE application or web servers - it's a source of a huge number of potential issues
Unfortunately, this is two different build processes, and most projects will use a single build system. It is a lot of effort for not a lot of benefit. You can initiate mvn package from eclipse as well. I would recommend maven since it is a standard. If you must do it, here are some ideas
In your startup process, test to see if /resources exists and prefix all paths with it
If its a single file, you can test and fall back on the second path
Tweak your pom.xml to put your resource folder at /resource

What is a good deployment directory structure for java console apps

I have a Java console application that I am ready to deploy onto a Unix server. I am writing a shell script to run the application.
I plan to put my shell scripts in one folder, my application jar and dependent jars (spring, etc.) into a different folder and properties files (those that need to be maintained 'live') in a separate folder again. I would then have my shell script iterate through the files in the 'jars' and 'properties' folders, appending them to the classpath, before finally calling java ...
Is this a 'good' deployment structure? Are there any guidelines for how to arrange files to maximise maintainability and stability? Are there obvious 'wrong' ways to do this that are best avoided?
I should add that, for a previous project, I put all shell scripts (those that start java processes and those that don't) into a scripts folder, my application jar into a folder with the library jars in a library subfolder and external resources into a config subfolder. I then wrote a script that explicitly loads all the files. It was long winded to write and needs to be maintained whenever I upgrade a library jar. This time around I'd like to do it better. Also, it feels unnecessary to separate my application JAR from the libraries.
For what it's worth, this is what we use;
/
/class
//package hierarchy here, raw .class files
/lib
//library jars here, apache commons, gson etc, all .jars
/conf
//.properties files go here, including ones for libraries
/doc
//program documentation files, typically .txt
/javadocs
//java doc html root
/sh
//shell scripts including execute.sh and compile.sh
We use ant for building, often have a src folder for the source tree if necessary. This way you just add /class and /lib to your classpath, and that never changes.
Good structure for your case is so called uberJar or oneJar, that can be made with number of utils, just google it. Also I can recommend such a nice piece of code as http://www.jdotsoft.com/JarClassLoader.php
Frankly, if it is just a small app, I would put it all under /opt/<my_java_app> and have a directory substructure there just like you did in dev.
If you want to be more compliant with the UNIX recommended practices, then put your executable (including your jar) in /usr/local/bin/<my_java_app>, config files in /etc/<my_java_app>, log files and other data files in /var/<my_java_app>.
Also, you may want to refer to this document.
Build a system-native package, and use system defaults. If using Debian, create a .deb direct from your build system (for instance, using ant deb task). If using rpms, use the rpm task. That way you can easily deploy, undeploy and update the application just like any other one.
The system package should separate libraries (I use /usr/share/java/AppName for my jars) and configuration (to /etc/AppName or /home/UserName/.AppName); the launch-scripts I symlink to /usr/bin. Beyond that, there is no great complication getting things to work. I recommend finding well-known java-based packages in your distribution and copying their launch scripts (in particular, their VM-locating magic).

Java - Difference between dist and deploy folders

Forgive me for a novice question, but what is the difference between the dist and deploy folders? It seems like the same thing - both contains the .jar of the files. However, when you clean and build the project, it looks like only the dist folder is updated. How does the deploy folder get updated?
Thanks.
I will assume that you are using a directory layout similar to what Netbeans IDE creates by default.
dist is the folder where your generated archives are stored (so it gets updated through clean and build).
build folder contains compiled classes and resources, but not the compressed archives.
Maven, by default, places the content of both into a target folder.
A deploy folder is the place where you put your generated artifacts (either archives or directory trees with the same layout as archives, a.k.a. exploded archives) so that you Application Server can serve it.
In development environments it is not unusual to configure the server to scan the dist folders for generated artifacts and redeploy them. So, in that sense, deploy and dist folders can be the same.
You can even have "in place" deployment scenarios. This works by compiling your classes direct to WEB-INF/classes folder inside webapp (with something like Maven war:inplace goal). If you set your server to scan changes in this folder, you can edit resources such as jps in place and have it immediately reflected into your running application (a.k.a. exploded artifact hot deployment).
Of course that you can accomplish something similar by instructing your IDE to copy resources and compiled classes to a exploded archive structure and configuring your server to scan it. Netbeans tends to use build/web for that purpose.
Also sometimes incremental redeployment is not possible and frequently full redeploys are not desirable (some applications may take several minutes to redeploy). That is why you can use separate folders / deploy your artifacts as jars / wars / ears, etc.
Compiling, packaging and deploying are very different phases / concepts of a Build lifecycle, which may or may not happen together.
I hope this is enough info to get you going.
Cheers,
Typically a project is responsible for creating one artifact, when that artifact gets built it is put in a directory called target or dist. When your project is responsible for creating a web application, you need a place to layout the files in your project to run under your servlet container or app server, and that place is the deploy folder. So the dist directory would typically have a single artifact like a war, ear or jar, while the deploy folder would have the contents exploded in a directory structure where the app server can use them. How the deploy folder contents get updated depends on your build process or IDE integration.

Should I commit WEB-INF into version control, or rather construct it with Ant?

The Ant "war" task does just that - creates WEB-INF along with META-INF, depending on task attributes.
What is considered a best practice?
Keeping all my libs elsewhere for re-use, like log4j and then build them with "war" task?
Or have everything (including jars) checked-in under WEB-INF?
I have multiple apps that could re-use same libs, images, htmls, etc. Our developers use RAD7/Eclipse.
I'd appreciate any examples with opensource Java Web Apps repo layouts.
If you can reliably, dynamically create it, the don't check it in. That's going to cause confusion. In this situation it's analogous to checking in .class files.
Rather, check in the build file and the artifacts you use to create it, and let the build take care of it.
I'd appreciate any examples with
opensource Java Web Apps repo layouts.
Here's an example of web application which is using a classic Maven directory layout:
hifaces20-demo-messageboard-0.1.0-project.zip
src
main
java
resources
webapp
WEB-INF
web.xml
test
java
resources
pom.xml
We work with Eclipse. I have found that having the files that Eclipse do not hide checked in work well for us. You check out the project, and you are ready to go. No further ant stuff to run or remember to run.
If you build with ant always (e.g. if you come from a Netbeans shop) then check in only those files which are original. All those that are copied from elsewhere, should explicitly be not checked in.
I generally do check in the WEB-INF folder but exclude the lib and classes folder. When I need the libs I retrieve them using Maven or Ivy (ant tasks). Seems to work well, I only check in the libs if it's an extreme case where it's likely I wont have an Ivy cache or the lib is 'special' and doesn't exist anywhere else.

Minimum directory structure and ant build file contents for Java web app

What is the minimal conventional directory structure for a Java web app? What do I need to put in a build.xml file to get ant to build it and make a WAR file?
My goal is to deploy a Wicket app to Tomcat without using an IDE. I want to do it with only ant and my favourite text editor.
Maybe not the most minimalist possible, but the Tomcat project has an Application Developer's Guide with a section on source layout and a sample build.xml
Also, if you are starting a new project, you might want to check out Maven. With Maven, rather than crafting your own build scripts, you adhere to standard layout to do stuff, and then Maven figures out all the rest. It also manages dependencies, including its own. Learning curve is a bit steep, though.
Ours look like this:
web/
web/WEB-INF/ (sometimes we use a conf/ dir at the top level but this is minimal)
src/
lib/
The build.xml has three targets:
jsp: copies everything from web/ into the tomcat webapp folder and from lib/ into WEB-INF/lib
compile: compiles everything from src/ into WEB-INF/classes in the webapp
war: runs compile, jsp, and then zips the contents of the tomcat webapp into a warfile
This structure is a little bit informal and you can do it more cleanly by having a separate build directory for the warfile, and/or a separate compile directory, etc. Some people don't like the idea of deploying directly to the webapp instead of building a war first. But to get something up and running quickly, the above will do nicely.
You should check out maven. It's really complicated, but to build a war file it's simple, and there are plugins that will deploy the war to tomcat.

Categories