Hello All,
after struggling for some days with establishing a proper JavaEE Application including techniques such as JSF, JPA and EJBs, I finally was able to to create a proper deployment that JBoss was able to process and it was GREAT.
Since I encountered many problems during that process and since I did not use any additionals tools using the “click-and-program”-principle to create myself the necessary ear, war and jar files, I wan’t to share my experience with you and tell you a little bit about the DOs and DON’Ts when implementing a JavaEE Application on top of JBoss without the help of any external tools (like in the good old days :)).
Prerequisites
“So what is this all about?”
My goal was to create an application that would compute the nation-wide holidays in Germany.
The concept was to:
- Have a View that retrieves a year and outputs all nation-wide holidays with names and dates.
- Realise this with JSFs
- In the back-end, i.e. the Model and Controller compute those holidays, store them to a database and load them again from it (a consistency check included – which is missing)
- Realise this with JPA and EJBs
Furthermore, before I start off, I would like to clearify / define the vocabulary I will use in the following.
- I will call those (annotated) Java Beans that are persisted by the Java Persistence API (short: JPA): Entity Beans
- I will call those (annotated) Java Beans that have states (@Stateless or @Stateful): Session Beans
- I will call a (not-annotated) Java-Class used by the JSFs: Controller
- I will call all other Java-Applications/Files: Will be named explicitly
I should mention that – as can be seen from the concept description – I built the system based on the Model-View-Controller (MVC) Principle. Moreover, I will describe how I realised those components in separate in the following, before I go into detail about the deployment of the system into JBoss or generally an application server.
Finally, before I describe the components, a brief overview over the system:
The View
I realized the View component using JSFs. I won’t go into detail about JSFs – in general – at this point, please look at the respective folders and files from the .zip file I upload with this article (I might add a JSF article later on).
However, the Workflow (which is of course important to understand the structure of the program and thus how to proceed for your project) of the interface was as follows:
Forwards to : Type in year : display holidays in that year
index.jsp -> trionaInput.jsp <-> trionaOutput.jsp
The Model
To implement the Model of my system, I decided to use the (relatively new) JPA. For this I needed Entity Beans and Session Beans.
Amongst the Entity Beans we had: TrionaDate.java and TrionaHoliday.java.
As a Session Bean I used the HolidayPersisterBean.java which implemented the HolidayPersister.java interface.
TrionaDate.java:
The concept was that a date has a list of holidays, thus there existed a @OneToMany relationship towards the TrionaHoliday Bean. The Date also has three further attributes. First the id which is not necessary, but recommended to have within a Entity Bean. Second, a Date Object containing the date and finally an integer holding the year of the particular date, to simplify later consistency-checks.
TrionaHoliday.java:
For the holiday, the concept was that each holiday has a date and since TrionaDate has a @OneToMany relationship to the holiday, the holiday has a @ManyToOne relationship to the date. Furthermore, each holiday has a name and of course an id.
HolidayPersisterBean:
The HolidayPersisterBean, is a Session Bean that is responsible for persisting and retrieving the Entity Beans (TrionaHolidays) for a given year.
The Controller
The Controller was represented by the HolidayController.java Class. This class works as a communicator between the View and the Model. The View accesses the local attributes (with getters and setters) of this Controller class, which again utilizes (e.g. for retrieving the holidays from the database) the HolidayPersisterBean. Furthermore, the controller makes use of the HolidayCalculator.java-Class, which actually does the computation of the holidays (how is not important at this point).
The Implementation/Deployment
Now That I have given you a little overview over the system-architecture, let’s have a close look at the actual deployment phase, which was the point at which I encountered the troubles.
In the following I will give you a step-by-step guide for deploying the system described above. I will also depict the final file structure and the minimal file structure – or directory-tree.
Ok, let’s start off.
Writing and categorizing the source files:
- The first thing one needs to do, is to identify the EJBs, i.e. what you believe falls into the category of being a Session Bean or an Entity Bean.
- I personally put the Session Beans under the sub-package named bean and the Entity Beans under the sub-package named model
- Thus I had the following package structure under src:
- ejb.bean.HolidayPersisterBean.java; ejb.bean.HolidayPersister.java
- ejb.model.TrionaDate.java;ejb.model.TrionaHoliday.java
- You could of course differentiate again between EJB categories (with sub-categories bean/model) resulting in e.g. holidayejb.bean; workejb.bean etc.
- Next I created a package for the controller, because that falls between the View and the Model and should be encapsulated.
- Hence we have under src:
- controller.HolidayController.java; controller.HolidayCalculator.java
- Hence we have under src:
- Finally I wrote the components for the View, i.e. I:
- Created a WEB-INF folder
- Created a web.xml file and inserted the required information to use JSFs
- Created a faces-config.xml (which I read somewhere is not necessary, but I like to choose the workflow)
- Created a “view” folder, where I wanted to store the faces (JSF files (have .jsp ending, but are addressed with .faces)
- Created the index.jsp file addressed in my web.xml file and
- A folder “faces”, where I stored
- trionaInput.jsp, trionaOutput.jsp
- A folder “faces”, where I stored
For the concrete code, please have a look at the attachement.
Up to this point no pitfalls (yay! :))
Deploying the application:
One more REMINDER, before I describe the deployment, generally I identified that my system has one EJB (the Model described above) and one Web-Application (the View described above). Further, NOTE that the Controller described above will be regarded as part of the View, since the HolidayController and its attributes are accessed by the JSFs and is therefore stored together with those.
Before you deploy your application you have to make a choice:
- Do you want to implement your EJB and Web-Application separately or not?
- Seperately – This implies creating a .jar file/folder and a .war file/folder:
- The .jar file/folder:
- “Why file/folder?”: Well, for JBoss it doesn’t matter whether you JARed together the necessary files and folders or if you create a folder with the following convention: $ejb_name$.jar, i.e. as long as it ends with .jar your fine.
- “What goes into the .jar file/folder?”:
- At the very least your classes with their folder/package structure intact (see example).
- If you use the JPA you MUST include a persistence.xml under a META-INF folder.
- NOTE: My EJBs were only registered properly when having the persistence.xml under META-INF, because I did not have an EJB without JPA usage. Therefore I say the very least, it might hold that more information is required, e.g. a MANIFEST.MF in the META-INF folder.
- The .war file/folder:
- “Why?”: Here holds the same as above, but please NOTE, that the name you choose for your .war file/folder, will be (unless defined otherwise by the web.xml) the name of your URL to this Web-Application.
- “What goes into the .war file/folder?”:
- At the very least a WEB-INF folder containing a web.xml file.
- However, you dont want an emtpy Web-Application, so feel free to insert into whatever folders you like your additional .jsp/JSF-files and your Servlet classes should be under the classes folder under WEB-INF (again see example).
- The .jar file/folder:
- Not Seperately – This implies creating an .ear file/folder and storing the .jar and .war along with an application.xml file (within a META-INF folder):
- “Why should I do this? It seems like alot more work!”:
- The most apparent reason I learned was, that using an ear file simplifies the collection of one-or-more .jar and .war files and helps to encapsulate information belonging together and allows a better overview over one’s Application.
- “That sounds reasonable, What should I do to create an .ear file/folder?”:
- Create .JARs and .WARs and store them into a .ear file/folder.
- (A MUST) Create a META-INF folder and add an application.xml into it.
- “Why should I do this? It seems like alot more work!”:
- Seperately – This implies creating a .jar file/folder and a .war file/folder:
Here is an example on how you would create the .jar and .war files/folders as I described above:
- feiertage_darsteller_ejb.jar
- ejb
- model
- TrionaDate.java
- TrionaHoliday.java
- controller
- HolidayPersisterBean.java
- HolidayPersister.java
- model
- META-INF
- persistence.xml
- ejb
- AND
- feiertage_darsteller.war
- WEB-INF
- classes
- controller
- HolidayController.java
- HolidayCalculator.java
- controller
- web.xml
- faces-config.xml
- classes
- view
- index.jsp
- faces
- trionaInput.jsp
- trionaOutput.jsp
- WEB-INF
Alternatively, you can let an ANT-script do all this for you, I did that. The respective build.xml is in the attachment.
This sounds straight forward and easy, well now it is, but until I reached this point I learned that
What you cannot do:
- Insert your own JSF libraries into the lib folder: WEB-INF/lib — causes: Cannot find Faces Context.
- Let your .jsp files point/forward to .jsp files, you need to call them $file_name$.faces.
- Using the Query API from the JPA (retrieved via the ContextManage.createQuery() method) to address your Entity Beans with their table names (you assigned with the @Table tag) in your formulated SQL (or rather pseudo-SQL) query. Here you MUST use the names of your Beans and the same holds for their attributes (i.e. @Column s).
- Not making your Entity Beans Serializable, and please use a generated serial UID (e.g. in Eclipse this can be done automatically).
- This is more like a INFO: If you get the NamingException Exception, look at your InitialContext.lookup(String ) methods, and ensure, that you are using the right path to address your EJB, if you are not sure, look at the console, it might look something like this: “feiertage_darsteller/HolidayPersisterBean/remote – EJB3.x Default Remote Business Interface”. If you don’t have anything like this, then your bean is not registered and you will also get the NamingException, then have a look whether you implemented the bean correctly! (In this case I suggest trying the minimal version of the .jar).
- Create an .ear file without an application.xml in the META-INF folder.
- Stuff the .jar file into the .war file (NOWHERE, believe me I tried 🙁 – feel free to correct me on this).
My final directory structure:
Best Regards,
David