Wednesday, December 14, 2011

AOP and Spring

Logging aspects and Spring.
Add this to your applicationContext.xml file.
 





service,logic,integration



loggingAdvice











  • This will cause the three beans, service, logic and integration to be logged.
  • This will cause the "bean" loggingAdvice to be exposed in the JMX console with the name TestLogging
  • This will expose the property enabled to the JMX console, set that to true and the aop starts to log.
Below is the complete Logging advice class.
package com.aja;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;

import com.ericsson.sdp.media.eup.charging.error.ErrorHandler;

import java.lang.reflect.Method;


/**
* Logging interceptor.
*/
public class LoggingAdvice implements MethodBeforeAdvice, AfterReturningAdvice,
ThrowsAdvice {
private boolean enabled = true;



/**
* Transcodeeates a new instance of LoggingAdvice.
*/
public LoggingAdvice() {
}

/* (non-Javadoc)
* @see org.springframework.aop.MethodBeforeAdvice#before(java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
*/
public void before(Method method, Object[] args, Object target)
throws Throwable {
if (!enabled) {
return;
}

StringBuffer builder = new StringBuffer();
builder.append("enter ").append(method.getName()).append("(");

for (int i = 0; args == null?false:(i < args.length); i++) {
builder.append(args[i]);

if (i < (args.length - 1)) {
builder.append(", ");
}
}

builder.append(")");

ErrorHandler.handleDebug(builder.toString());

}

/* (non-Javadoc)
* @see org.springframework.aop.AfterReturningAdvice#afterReturning(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
*/
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
if (!enabled) {
return;
}

ErrorHandler.handleDebug(RETURN + method.getName());
}

/**
* @param method
* @param args
* @param target
* @param exc
*/
public void afterThrowing(Method method, Object[] args, Object target,
Throwable exc) {
if (!enabled) {
return;
}

ErrorHandler.handleDebug("return " + method.getName() + exc.getMessage());

}

/**
* @return the enabled
*/
public boolean isEnabled() {
return enabled;
}

/**
* @param enabled the enabled to set
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

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.

4.0.0
Maven Default Project
com.aja.myportlet
MyPortlet
1.0
pom

MyPortlet.war




org.apache.maven.plugins
maven-compiler-plugin

1.5
1.5




The pom.xml in the MyPortlet.war directory shall look like this.

4.0.0

com.aja.myportlet
MyPortlet
1.0

MyPortlet.war
war


junit
junit
4.1
test


log4j
log4j
provided
1.2.13


javax.servlet
servlet-api
2.5
provided


opensymphony
xwork
2.0.1


commons-logging
commons-logging
1.0.4


commons-attributes
commons-attributes-api
2.1


commons-collections
commons-collections
3.2


freemarker
freemarker
2.3.4


org.apache.struts
struts2-core
2.0.6


asm
asm
1.5.3



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









/WEB-INF/pages/view/helloForm.jsp


/WEB-INF/pages/view/helloForm.jsp


/WEB-INF/pages/view/helloWorld.jsp



jboss-app.xml


MyPortlet

jboss-portlet.xml





MyPortlet-object.xml


portlet.xml




My very first struts Portlet
MyPortlet
My first WebWork Portlet

org.apache.struts2.portlet.dispatcher.Jsr168Dispatcher



viewNamespace
/view



defaultViewAction
index


0


text/html


en


My very own WebWork Portlet
WWPortlet
struts,portlet


web.xml






struts

org.apache.struts2.dispatcher.FilterDispatcher




struts
/*




org.apache.struts2.portlet.context.ServletContextHolderListener





preparator

org.apache.struts2.portlet.context.PreparatorServlet




/struts-tags
/WEB-INF/struts-tags.tld


helloForm.jsp

<%@ taglib uri="/struts-tags" prefix="ww" %>

Hi there! Please enter your name







helloWorld.jsp

<%@ taglib uri="/struts-tags" prefix="ww" %>

Hello



">Back to form

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" %>







Wddfsd


























Please Enter the Following Details

Name



Save

Cancel




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" %>





Sucess











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

This is simple step by step tutorial on how to build an application that will display content on web pages. Everything will be done in a pedagogic simple way.The nuild is done with the Apache Maven framework instead of ant.

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)
Services is the main xfire configuration file. In here you tell the system which service is to be published. In our case the service is called BookService. Quite fitting when it comes to my big interest, books.

Step 6. The service.xml file content

The file might look like this.


BookService
http://xfire.codehaus.org/BookService
se.aja.xfire.BookService
se.aja.xfire.BookServiceImpl


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.


XFireServlet
XFire Servlet

org.codehaus.xfire.transport.http.XFireConfigurableServlet




XFireServlet
</servlet/XFireServlet/*



XFireServlet
/services/*

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




/book

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;

book

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;

book-jar

book-war

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;

book-jar

book-war

aspect


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


aspectj
aspectjrt
1.5.2a
provided


org.aja
book-jar
1.0.0
provided


org.aja
book-war
1.0.0
provided

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.




org.codehaus.mojo
aspectj-maven-plugin



compile




1.5
1.5


org.aja
book-jar


org.aja
book-jar







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 /classes directory.

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");

}

}