Join GitHub today
How do I add a page to the Java based site?
Adding a page to the rhn-java website is a fairly straight-forward and simple process, however, it isn't as easy a plopping a file into a directory. There is an architecture involved, and while it may seem like a lot of overhead just to create a dumb web page, adhering to this architecture/framework will help us scale the site and maintain separation of concerns.
*** Do not commit any of the following code or face ridicule.*
*** $RHN-JAVA is the git checkout of the spacewalk-java site.*
Let's walk through an example.
Let's create the jsp. First, create a
mkdir -p $RHN-JAVA/code/webapp/WEB-INF/pages/test cd $RHN-JAVA/code/webapp/WEB-INF/pages/test
Inside of the new test directory, create a file called
hello.jsp with the following contents:
#!text/html <html:xhtml> <body> <h1>Hiddy Ho!</h1> <h2>A hello world test page by: your name here</h2> <p>Hello my name is mud.</p> </body> </html>
Ok. This is a pretty simple example of a standard html file. To use
tags, you must first import the taglib. If you don't know how to do this, I
recommend you read 1,2 or look at some of the existing pages for examples.
Now we need to open up the
and add an action forward to our page. There are several architecture decisions that should be discussed here.
Why do we put pages in WEB-INF?
This is to protect your jsp from being accessed by some yahoo typing in
WEB-INFis protected by Tomcat and so we can't serve pages, in the traditional sense, out of it. This may seem like a moot point considering our simple hello-rhn page, but consider a form which may need a
SetupActionor some other processing to occur before the page is rendered.
Why do we map every page?
Besides the points outlined above, mapping pages promotes re-use and easy management. For example, say we needed a hello-rhn page under the systems tab, users tab, and on the index page. We could now include the page portal-style on the index, and map systems/Hey.do and users/hello/Howdy.do both to the same hello.jsp.
So, on with the show.
Add the following to the struts-config.xml file:
<action path="/hello/HelloRhn" forward="/WEB-INF/pages/test/hello.jsp" />
There are a few things to notice about the path attribute of the action tag
above. First, note that it is completely random. We could have used
/yankee/doodle/Dandy and as long as the url accessed was
/yankee/doodle/Dandy.do it would have mapped to our new jsp.
This brings me
to the second note you should make about the mapping; The path doesn't include
the ".do" extension. This is because there are multiple ways to tell Tomcat
that a given url should be processed by Struts. Common standards include
<action-name>.do. The important thing here is to
realize that the
.do extension could be changed at any time and isn't
important to the action-servlet.
Restart Tomcat (to pick up the struts-config changes) and go to
and you should see your new page! Don't forget NOT to check this in!
WHAT ARE FRAGMENTS?
JSP Fragments are a simple naming convention from 1, and are meant to
specify that a jsp is not to be used on its own. For example, a .jspf file may have a jstl or rhn tag in it and require that the page using the fragment declare the taglib for it.
Fragments are used throughout our jsps wherever we have a piece of code that should be reused across several jsp pages. Fragments are located under
and have a .jspf file extension rather than the usual .jsp.
HOW DO I ADD/PROCESS A FORM?
Instead of creating our own, I'm going to use the user edit functionality of
the current rhn-java code to demonstrate the needed components. A form page, by definition, will take input from the user and do something with it. Because of this, each form/situation will be unique and therefore will require you to either look at existing examples on the site or consult a reference book [REF 3].
For the most part, rhn-java uses
DynaActionForms instead of
allows us to define the form in our struts-config.xml and have a dto class
generated for us, that will handle moving data between the form and the action
class. Find the following in
<form-bean name="userDetailsForm" type="org.apache.struts.action.DynaActionForm"> <form-property name="uid" type="java.lang.Long"/> <form-property name="firstNames" type="java.lang.String"/> <form-property name="lastName" type="java.lang.String"/> <form-property name="title" type="java.lang.String"/> <form-property name="prefix" type="java.lang.String"/> <form-property name="password" type="java.lang.String"/> <form-property name="passwordConfirm" type="java.lang.String"/> <form-property name="possibleRoles" type="org.apache.struts.util.LabelValueBean"/> <form-property name="selectedRoles" type="java.lang.String"/> </form-bean>
This defines a form bean. Each form-property corresponds to an input field on
the form. Struts handles the type conversions for you. Next we will define
paths to help us setup/process the form. Find the following in
<action path="/network/account/UserDetails" name="userDetailsForm" scope="request" input="/WEB-INF/pages/user/edit/yourdetails.jsp" type="com.redhat.rhn.frontend.action.UserEditSetupAction"> <forward name="success" path="/WEB-INF/pages/user/edit/yourdetails.jsp"/> </action> <action path="/network/account/UserDetailsSubmit" name="userDetailsForm" scope="request" input="/WEB-INF/pages/user/edit/yourdetails.jsp" type="com.redhat.rhn.frontend.action.UserEditAction"> <forward name="success" path="/network/account/UserDetails.do" redirect="true" /> <forward name="failure" path="/network/account/UserDetails.do" /> </action>
It is a best-practice/rhn-convention to name your paths and actions like this.
The first time a user would see a form, the action is named regularly, but uses
*SetupAction for its type. This means that when a user types
/network/account/UserDetails.do into their browser, this path is called and
UserEditSetupAction is called. After the
SetupAction has finished
successfully, the yourdetails.jsp page is displayed.
Check out the yourdetails.jsp page. Note that the form's action is
UserDetailsSubmit. This means that when the form is submitted, we will run the
UserDetailsSubmit action defined above and the
UserEditAction will get called. If successful, we forward to
UserDetails.do. Notice the
redirect="true" attribute. This means that we are doing a full redirect to the next page. If you are confused about the differences between a forward and a
redirect, see 1, 2.
Ok. So now is probably a good time to conceptually step through the process of what is going on behind the scenes so that you can get a good feel for what these mappings are doing.
- A user clicks on an "edit details" link from someplace. The url
/network/account/UserDetails.dois requested to Tomcat and forwarded to the Struts action servlet. At this point, Struts gets a
userDetailsForm DynaActionFormand forwards that, along with the request, to
UserEditSetupActiongets the user from the request and pre-populates our form by using the setters defined by our
userDetailsFormbean. Note that near the end of the class, we create a new variable and put it into the request.
yourdetails.jspform is displayed. Note that we use a fragment to display some of the elements in the form. This is because the same jsp code is used elsewhere. Also, note that we are getting the
availablePrefixesvariable out of the request that was set by our
- When the form is submitted the url
/network/account/UserDetailsSubmit.dois called. This calls the
UserEditActionclass with the form. In this class we perform the editing of a the users info and return a "success" note that if we find any errors, we add them to
ActionErrorsand return a "failure". The
ActionErrorsis a way to send error messages from our action, back to the page.
That's it. Fairly simple. To familiarize yourself with all of the different types of things you can do, please investigate the existing source code yourself.
In particular, the
LookupDispatchAction class is very powerful and can be used to do CRUD operations on an object all from a single form!
- "JavaServer Pages (3rd ed.)" - Bergsten
- "Core Servlets and JavaServer Pages (2nd ed.)" - Marty Hall
- "Struts In Action" - Husted