Logging aspects and Spring. |
Add this to your applicationContext.xml file. |
|
|
Below is the complete Logging advice class. |
package com.aja; |
aspemo
Wednesday, December 14, 2011
AOP and Spring
Struts2 and portlet
This is a short how to get a Struts2 application up and running in JBoss portal framework.
We will use the following tools one at a time in this tutorial.
Tools:
JBoss 4.0.5 with the portal extension.
Maven 2.0.4
Struts 2.0.6
Ubuntu Edgy Eft
Java 5.
Note this. There is a fundamental difference between Struts1 and struts2. The whole concept is changed and Struts has moved
away from the straight flow based approach to a more object oriented way with dependency injection. There are a multitude of sites about this, but the best staring point is probably the Struts homepage.
So before starting. The disclaimer is that in a serious production environment, this application will not be enough. This is just a test for the home cooker.
Step 1.
Install JBoss 4.0.5 and pick the one with version number 4.0.5 and choose Run Installer. That's right, make sure you choose "Run Installer".
Pick installation language.
This should be standard stuff. You go next all the time and accept the license agreement (well, only if you accept it of course). pick installation directory.
For the sake of argument I choose /jbossportlet. Pick your choice and then press next.
let the installation program create the directory. Press ok.
You have to choose protal here.
In your jbossportal/bin directory there are two files of interest.
run.sh and run.conf make a copy of each and name them debug.sh and debug.conf. Edit debug.sh and find the one and only occurence of the word run.conf in the file. Change this to debug.conf.
Now change the debug.sh file and remove the bracket# in fron ot the line where it says something like this,
#JAVA_OPTS="$JAVA_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y"
When youe are done the ine should be like this
JAVA_OPTS="$JAVA_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y"
OK. Test JBoss now go to the installation directory/bin and type ./run.sh this should fire up your JBoss app server.
To see if it works type http://localhost:8080/portal and the JBoss portal page should appear. Do not panic if it takes a while. If you do not see this page
without errors do not bother to proceed, something is major wrong at your place right now.
Maven
Install Maven go to Mavens home page.
I used version 2.0.4. Not that it really matters, but version numbers are important in ceratin circles.
There is a web.xml file in the WEB-INF directory, if you don't do this Maven doesn't build your web app.
Add one pom.xml to the main MyPortlet directory and add one pom.xml to the MyPortlet.war directory.
The content is as follows.
The top pom.xml shall look like this. This is the pom in the MyPortlet directory.
The pom.xml in the MyPortlet.war directory shall look like this.
Go to the MyPortlet.war directory and exceute this command.
mvn clean install
Eclipse.
I assume you know Eclipse. Otherwise you are in for a long journey. Now make the eclipse project file in maven by
executing this mvn eclipse:eclipse.
Import the project. You must define your Maven repository in the Eclipse class-path setting. The variable is called M2_REPO and you must point to your Maven repository. If you are unsure check out the Maven documentation.
In windows most of the time you'll find the REPO in the Documents folder.
Coding
When we are done the following files will exist in our project.
In the WEB-INF directory
jboss-app.xml
jboss-portlet.xml
MyPortlet-object.xml
portlet.xml
web.xml
I also felt a need to add this tld as well. It can be found in the Struts2.0.6.core jar in the /META-INF directory.
I don't think you need them but I have to verify that.
struts-tags.tld
In the src/main/resources directory
struts.xml
In the WEB-INF/pages/view (Yes you must create that directory)
helloForm.jsp
helloWorld.jsp
And we'll do one Java class and put it in
src/main/java/com/aja/mp/action/HelloWorldAction.java
The content of all files (except tlds) will be shonw below. If you add this content your application will work.
struts.xml
jboss-app.xml
jboss-portlet.xml
MyPortlet-object.xml
portlet.xml
web.xml
org.apache.struts2.dispatcher.FilterDispatcher
org.apache.struts2.portlet.context.ServletContextHolderListener
org.apache.struts2.portlet.context.PreparatorServlet
helloForm.jsp
<%@ taglib uri="/struts-tags" prefix="ww" %>
Hi there! Please enter your name
helloWorld.jsp
<%@ taglib uri="/struts-tags" prefix="ww" %>
Hello
HelloWorldAction.java
package com.aja.mp.action;
import java.util.Collection;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport {
/**
*
*/
private static final long serialVersionUID = 2452536171755317259L;
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
return super.execute();
}
@Override
public Collection getActionMessages() {
// TODO Auto-generated method stub
return super.getActionMessages();
}
}
We are done, build and deploy the application.
mvn clean install
Rename and copy war to /jbossportal/server/default/deploy/MyPortlet.war
You will most probably get two errors at start up time, you can ignore those if it one complaining about a dev property and another complaining about i18.
Struts
This is a short how to get a Struts application up and running.
The following run time configuration was used
jdk1.5.0_09
Jboss4.0.5
Ubuntu Edgy Eft
The following development environment was used
Eclipse3.2.2
Web Tools plugin 1.5.1
Struts version used is 1.3.8.
If you need a more thorough explanation on the MVC2 pattern browse the net.
You need some things to get it to work. First off the struts-config.xml file.
This file should be in the WEB-INF directory. Remember, WEB-INF makes the file inaccessible to the outside world.
Well, well what does all that mean.
First off a form-bean. And now, what does a form bean do? It basically means that
if you post data Struts make sure that your parameters are sent to the server and handled there.
For instance if you post a user name that name will be sent to the server, and the instance of the form class will use getters/setters and use that.
All form beans must extend the org.apache.struts.action.ActionForm; Please override the validate method since this makes it possible for you
to handle erroneous data in a good way. I have implemented the reset method as well.
my form bean
public class StartForm extends ActionForm {
/**
*
*/
private static final long serialVersionUID = -3219629289363196387L;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* Reset all properties to their default values.
*
* @param mapping The mapping used to select this instance
* @param request The servlet request we are processing
*/
public void reset(ActionMapping mapping, HttpServletRequest request) {
this.name=null;
}
/**
* Reset all properties to their default values.
*
* @param mapping The mapping used to select this instance
* @param request The servlet request we are processing
* @return errors
*/
public ActionErrors validate(
ActionMapping mapping, HttpServletRequest request ) {
ActionErrors errors = new ActionErrors();
if( getName() == null || getName().length() < 1 ) {
errors.add("name",new ActionMessage("error.name.required"));
}
return errors;
}
Ok, now we are done with the Form. This is the Model aprt of the pattern. The model can be seen as a stupid data carrier.
We'll take the action now.
public class StartAction extends Action {
package com.aja.lib.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
ActionErrors errors = form.validate(mapping, request);
if (errors.size() > 0){
return mapping.findForward("fail");
}
return mapping.findForward("success");
}
}
As you can see, extend the org.apache.struts.action.Action class and override the execute method. You have two different outcomes. In case of a success go to
"success" and in case of error go to "fail". These two paths must be mapped in the struts-config.xml file. Remember this code.
The action in our case is where you usually put your calls to the tiers behind the presentation tier, i.e business tier. This is the C in MVC, the control part, the traffic handler.
What about the View? Well, look above in the code "success.jsp" and fail.jsp that's our views. They must exist.
First off the start point that we defined in the struts-config.xml, start.jap
<%@ page language="java" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>
Please Enter the Following Details | |
Name | |
Now here we see some magic. Note the html:text property="name", this will be mapped towards our form beans setName method.
I made it simple here, success just forwards to a stupid empty page, and fail back to start.jsp. below is my success.jsp
<%@ page language="java" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>
Deploy it and write http://locahost:8080/LibWeb/start.jsp. Good luck now.
One final word, if you develop something for real, you will most likely for instance not have a .jsp instead you can add in the configuration a lot of default handling stuff.
Create a simple JavaEE application with XFire
Below is a small list of tools used. All fancy words or strange settings will be omitted. In 90% of the applications you build you can use the default settings and they will work.
This tutorial contains these parts;
Part 1 - Create a stand alone application accessing a database with Hibernate.
Part 2 - Add web pages and access the database by calling methods on the application built in part 1. Deploy it on a server.
Part 3 - Change the application to use a datasource instead of a driver manager.
Part 4 - Add Ajax to interact with server.
Part 5 - Add ejb to use as a session facade to the methods created in part 1.
I used hiberate as the orm mapping system. Nobody uses raw sql anymore, at least not professionally. Many use the new JPA standard that was introduced together with EJB3.0 (which indirectly use TopLink or Hibernate). Most of the time I use JPA as well and use the underlying implementation on the application server. For JBoss default is Hibernate and for Sun it is Oracles Toplink. In this tutorial we use the "old fashioned" Hibernate directly.
Tools used
Eclipse 3.3.1.1 - to edit files
MySql 5.0.5 to store content
Maven 2.0.9 - to build project
Part 2 Apache 2.0 - to run web application
Part 2 Tomcat 5.5.17 - to execute java code
Part 5 JBoss 5.0.0 - to run Java EE app
Tutorial One, create a web service project with XFire
This tutorial will show how you can create an application with XFire from Codehouse. It will not access the database and it will have hardwired properties.Note that today most people use the JAX-WS API directly in the Java EE and do not use aweb service framework at all.
Step 1. Create project
People do this differently, but this is how I do it. Create three folders, call the first one book, add two folders within this one, call them bookjar and bookwar. The war project is not needed for the moment.
I always add a suffix to my projects to indicate which type of packaging to use, jar, war, ejb or ear. In each folder add a file called pom.xml.
Step 2. Create pom files in each folder
In the top folder book add this pom file whichjust define some aspects of the project. Note that there is probably as many ways as there are developers out there when it comes to writing pom files.
As you can see I have already added the MySql to the pom because I know I will need it later.In the bookjar folder add this pom file.
In the bookwar folder add this pom file.
Step 3. Create files needed for the build
Now you are almost done. First, before you can build the application you must have directory structure.
The jar project shall have this structure;
- src/main/java
- src/main/resources
- src/test/java
- src/test/resources
The war project must have this structure;
- src/main/java
- src/main/resources
- src/test/java
- src/test/resources
- src/main/webapp/WEB-INF
- src/main/webapp/META-INF
It is very important to understand that Maven will not be able to build the application without a web.xml file in the WEB-INF directory. This is just a simple plain one.
If maven do not find the dependency jars you must install them into your repository. Note. Sometimes it can be a bit confusing or some overhead to get Maven to work. For instance you might need jar files which do not exist in the maven repository. These will have to be installed manually. Do not give up, it is worth the extra job. After that you will notice how much easier it is to run the build process.
What we need to do now is create the "stuff" we will work with. I will not go into the details, instead see the import statement in the file header, these will indicate where these files shall reside. I.e. in which java packages they are expected to be found.
Step 4. Create java files needed in the application
Write eclipse:eclipse and import the projects into Eclipse.
We will create 3 java files.
- se.aja.xfire.Book.java (java class)
- se.aja.xfire.BookService.java (java class)
- se.aja.xfire.BookServiceImpl.java (java interface)
One is our domain object (book), this is what the site is about, books. Since it is so small we use the same object from the database out to our jsp pages.This is one strategy, the other is to convert the objects before displaying them.Two is the service. Put all these objects in the jar project. Thus when you are done in the jar project you shall have these files;
- src/main/java/se/aja/xfire/Book.java
- src/main/java/se/aja/xfire/BookService.java
- src/main/java/se/aja/xfire/BookServiceImpl.java
Step 5. Create XFire service file and modify web.xml
You will need to add the XFire services.xml file to the META-INF directory. When you are done in the war project it shall look like this.
- src/main/webapp/WEB-INF/web.xml (standard web app file)
- src/main/webapp/META-INF/services.xml (XFire configuration file)
Step 6. The service.xml file content
The file might look like this.
The service class indicates which service to publish and the implementation class is the concrete class implementing the interface.
One strange thing occurd to me, and is is also written about it on codehaus. I got a file not found error. I followed this instruction and got it to work.
Try "WEB-INF/classes/META-INF/xfire/services.xml" if the system cannot find the file. I.e. add a directory META-INF into the classes directory and add the services.xml there.
Step 7. The domain object (Book.java)
Let's assume the book class just contain an author and a title. It might look like this then. Pls. ignore the obious bad programming regarding null pointers and whatsoever. This is a pojo.
package se.aja.xfire.Book;
import java.io.Serializable;
public class Book implements Serializable{
private String author;
private String title;
public String getAuthor() {
return this.author;
}
public void setAuthor(String author) {
this.author = auhtor;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
}
Step 8. The service definition (BookService.java)
BookService.java - Our service interface, remember S(ervice)OA.
The service just publishes some methods.
public interface BookService extends Serializable {
public List getBooks();
}
Step 9. The service implementation (BookServiceImpl.java)
BookServiceImpl.java - Our class implementing the interface.
public class BookServiceImpl implements BookService {
private List books;
public BookServiceImpl(){
books = new Arrayist();
Boook b1 = new Book();
b1.setAuthor("Jonas");
b1.setTitle("Blaha");
Boook b2 = new Book();
b2.setAuthor("Aspemo");
b2.setTitle("Blaha again");
books.add(b1);
books.add(b2);
}
public List getBooks(){
return books;
}
}
Step 10. Configure the web.xml file to handle XFire
You have to add the xfire servlet to your web.xml file. Add the following between the webapp tag in that file.
org.codehaus.xfire.transport.http.XFireConfigurableServlet
<
Your web.xml file should look like this now.
Step 11. Fix context root for Sun Application Server
Your application will default to the name of the war, i.e. war-1.0.0. If you want to define a context name do like this.
Add sun-web.xml file to the WEB-INF directory and add this code there
if running on a Sun Application Server or add a jboss-web.xml into the
Step 12. Fix context root for JBoss Application Server
Your application will default to the name of the war, i.e. war-1.0.0. If you want to define a context name do like this.
Add jboss-web.xml file to the WEB-INF directory and add this code there;
Step 13. Deploy the application
Run the web application by deploying it to your favourite servlet container.
Type,
http://localhost:8080/book/services/BookService?wsdl and you see your exposed web service.
That is what the default context name should be.If you are unsure and wants to define context.
Your first xfire app is working. Test the methods with SOAP UI. Take a break. Drink a coke or a coffee.
Step 14. What's left
Well most obviously we lack the functionality to access things in the database. The Book file is hardwired with some data. That
EJBPoolSize
I had a discussion on the EJB Pool size on a Sun Application Server. The documentation is a bit vague (to say at least) on how it really works.
First the definition. The EJB pool size is a way for the EJB container to create (pool) stateless session beans to serve client requests. The max pool size do sound a lot like a theoretical limit on how many request that can be served simultaneously. But that is not so actually. This is just a number on how many EJBs that are pooled over a long run. If more requests comes in, more beans are created. So, even if you have 200 as a max size, 500 clients can be served at the same time. Interesting?
The annotation @PostConstruct will show you the meaning of the pool. If you have a pool size of 5, you send in 10 simultaneous 10 calls to the @PostConstruct will be shown, BUT, the next request coming after say 1 second will not call @PostConstruct since those pools are pooled and the @PostConstruct are called before the bean is created and used by a client. This is the implications of the pool size.
Note also that the pool handling is application vendor specific. This is tried and verified on a Sun Application Server version 9.1.
I will let you create the project by yourself since that is no issue. In the ejb I added these methods.
@PostConstruct
public void createIdentity(){
System.out.println(" PostConstruct ");
}
This will print out the row PostConstruct every time an ejb is created. And yes, I would naturally never use Sys out in a real enterprise project.
public String getTimerName(){
System.out.println("Get Timer Name");
try
{
Thread.sleep(10000);
} catch (Exception e)
{
e.printStackTrace();
}
return "Jonas A";
}
This will sleep the thread for 10 seconds.
Next I changed the pool size setting in the App server to be max 5.
Then I made a servlet with this method in;
long start = System.currentTimeMillis();
InitialContext ic = new InitialContext();
BookService bk = (BookService) ic.lookup("Jonas");
bk.getTimerName();
long end = System.currentTimeMillis();
diff = end - start;
No matter how many simultaneous calls you make this method only takes 10 seconds and the trace shows that the app server creates as many PostConstruct statements as simultaneos calls, no matter how many they are.
After a time you might notice new PostConstruct statements even if you only make one call. This is because pooled instances are discarded after a while. A new flag STEADY_STATE can configure this behaviour as well.
Aspects and Maven
Many times you might want to implement restrictions on what developers are allowed to do. For instance, you might want to prohibit the usage of System.out in Java EE applications.
One way is to add triggers in your version control system. Another way is to add aspects. This short how to shows what you need to do the get aspects working.
Step 1
Create a new project, and add it to the super pom. Thus if you want to build a book application your super pom might look like this;
Now add the new project which will contain your aspects, call it for instance aspect (or whatever).
your super pom shall look like this now;
Create the aspect project with normal directory structure.
src/main/java/org/aja/aspect/
In the aspect directory we shall add our restriction;
Let's call it DoNotPrint.aj
File DoNotPrint.aj
public aspect DoNotPrint {
private pointcut withinBook() : within(org.aja..*);
declare error:
withinBook() &&
get(* System.out):
"Accessing System.out is not allowed.";
declare error:
withinBook() &&
get(* System.err):
"Accessing System.err is not allowed.";
declare error:
withinBook() &&
call(* java.lang.Throwable.printStackTrace()):
"Calling Throwable.printStackTrace() is not allowed.";
}
The file says that it shall weave all files in the package structur org.aja and send an error when it finds a System.out. Change decalre error to declare warning if you think that is sufficient.
Now manipulate the pom.xml in the aspect project. The super pom is finished.
Step 1, add a dependency to the proper aspect jar and all projects we shall weave
So, we added both a dependency to the aspect jar which is needed for all operations and the two projects we want to verify, or weave.
Add this to the build tag.
That's it. Everytime you stand in the top of the project and build the book-jar, book-war and aspect it will browse through all your classes and the build will fail with an error message if it finds any instances of System.out in the code.
Classpath
If you don't work in an IDE, such as Eclipse or Netbeans, where do you put your java files?
The answer is in your
Step 1
Let's assume you create a class called DumbNumber which prints a digit.
public class DumbNumber {
public static void main(String...args) {
System.out.println("Dumb number is 7");
}
}