Tuesday, October 07, 2008

(ISO 8583 + JPOS + Log4J) in Java Socket Programming

SECTION 1. INTRODUCTION
Chapter 1.1. ISO 8583
You can read it's explanation first in Wikipedia.
Chapter 1.2. JPOS
JPOS is opensource framework for ISO 8583. Source code and library are free but documentation is comercial. We can download it here.
Chapter 1.3. Log4J
Log4J is opensource logging library. We can download it's library here and read it's mini e-book first written by Mr. Endy in here.
Chapter 1.4. Java Socket Programming
There's no explanation. Just need the basic knowledge of Java network programming and Java Thread Programming and let's coding.

SECTION 2. CODING
First we prepare that all we need. In this time, we will use NetBeans as IDE. Besides JPOS framework and Log4J library that I have mentioned above, we still need:
1. Xerces-Java XML parser library (xercesImpl.jar)
2. Spring framework
3. Jakarta Apache Commons Logging library

Chapter 2.1. ISO 8583 + JPOS + Log4J
In NetBeans, create a new Java application named MyApp. Create a package named com.ndung.iso8583. JPOS framework need a packager to set which ISO 8583 version that will be used. In this time we will use ISO 8583 version 1987. Download first iso87ascii.xml and place it in that package. Create a class as packager factory named PackagerFactory.java.


package com.ndung.iso8583;

import java.io.InputStream;

import org.jpos.iso.ISOException;
import org.jpos.iso.ISOPackager;
import org.jpos.iso.packager.GenericPackager;

public class PackagerFactory {
public static ISOPackager getPackager() {
ISOPackager packager = null;
try {
String filename = "iso87ascii.xml";
InputStream is = PackagerFactory.class.getResourceAsStream(filename);
packager = new GenericPackager(is);
}
catch (ISOException e) {
e.printStackTrace();
}
return packager;
}
}

And then create a class named MessageHandler.java that will be used to handle received message. Download first iso87asciiProperties.xml that will be used to translate bits of ISO message to become a String message that can be read easily.


package com.ndung.iso8583;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.jpos.iso.ISOException;
import org.jpos.iso.ISOMsg;
import org.jpos.iso.ISOPackager;

public class MessageHandler {
private static ISOPackager packager = PackagerFactory.getPackager();
private Logger logger = Logger.getLogger( getClass() );
public String process(ISOMsg isomsg) throws Exception {
logger.info("ISO Message MTI is "+isomsg.getMTI());
logger.info("Is ISO message a incoming message? "+isomsg.isIncoming());
logger.info("Is ISO message a outgoing message? "+isomsg.isOutgoing());
logger.info("Is ISO message a request message? "+isomsg.isRequest());
logger.info("Is ISO message a response message? "+isomsg.isResponse());
String message = "";
for (int i=0;i<128;i++){
if (isomsg.hasField(i)){
message += loadXMLProperties().getProperty(Integer.toString(i))+"="+
isomsg.getValue(i)+"\n";
}
}
logger.info(message);
return message;
}

public ISOMsg unpackRequest(String message) throws ISOException, Exception {
ISOMsg isoMsg = new ISOMsg();
isoMsg.setPackager(packager);
isoMsg.unpack(message.getBytes());
isoMsg.dump(System.out, " ");
return isoMsg ;
}

public String packResponse(ISOMsg message) throws ISOException, Exception {
message.dump(System.out, " ");
return new String( message.pack() ) ;
}

public Properties loadXMLProperties(){
Properties prop = new Properties();
try{
FileInputStream input=new FileInputStream("iso87asciiProperties.xml");
prop.loadFromXML(input);
input.close();
}
catch(IOException e){
e.printStackTrace();
}
return prop;
}
}

Chapter 2.2. Java Socket Programming + Log4J
Create a package named com.ndung.socket and then create four classes named ServerConfig.java, SocketServerHandlerFactory.java, SocketServerHandler.java, SocketConnectionServer. Before that create log4j.properties as logging configuration in default package.

# Category Configuration
log4j.rootLogger=INFO,Konsole,Roll
# Console Appender Configuration
log4j.appender.Konsole=org.apache.log4j.ConsoleAppender
log4j.appender.Konsole.layout=org.apache.log4j.PatternLayout
# Date Format based on ISO­8601 : %d
log4j.appender.Konsole.layout.ConversionPattern=%d [%t] %5p %c ­ %m%n
# Roll Appender Configuration
log4j.appender.Roll=org.apache.log4j.RollingFileAppender
log4j.appender.Roll.File=/home/ndung/NetBeansProjects/MyApp/log/myApp.log
log4j.appender.Roll.MaxFileSize=10KB
log4j.appender.Roll.MaxBackupIndex=2
log4j.appender.Roll.layout=org.apache.log4j.PatternLayout
# Date Format based on ISO­8601 : %d
log4j.appender.Roll.layout.ConversionPattern=%d [%t] %p (%F:%L) ­ %m%n


package com.ndung.socket;
public class ServerConfig {
private int port;
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}


package com.ndung.socket;

import com.ndung.iso8583.MessageHandler;
import java.io.IOException;
import java.net.Socket;

public class SocketServerHandlerFactory {
private MessageHandler messageHandler;
public SocketServerHandlerFactory(MessageHandler messageHandler) {
this.messageHandler = messageHandler;
}
public SocketServerHandler createHandler(Socket socket) throws IOException {
return new SocketServerHandler(socket, messageHandler);
}
}


package com.ndung.socket;

import com.ndung.iso8583.MessageHandler;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import org.apache.log4j.Logger;
import org.jpos.iso.ISOMsg;

public class SocketServerHandler extends Thread{
private Logger logger = Logger.getLogger( getClass() );
private Socket serverSocket ;
private BufferedReader inFromClient;
private DataOutputStream outToClient;
private MessageHandler messageHandler;
private String datafromClient;

public SocketServerHandler(Socket socket, MessageHandler messageHandler) throws IOException {
super("SocketHandler (" + socket.getInetAddress().getHostAddress() + ")");
this.serverSocket = socket ;
this.messageHandler = messageHandler;
this.inFromClient = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
this.outToClient = new DataOutputStream(serverSocket.getOutputStream());
}
@Override
public void run() {
try {
logger.info("Server is ready...");
while (true) {
logger.info("There is a client connected...");
outToClient.writeBytes("InfoServer version 0.1\n");
datafromClient = inFromClient.readLine();
logger.info("Data From Client : "+datafromClient);
ISOMsg isomsg = messageHandler.unpackRequest(datafromClient);
outToClient.writeBytes(messageHandler.process(isomsg));
}
}
catch (IOException ioe) {
logger.error("error: " + ioe);
}
catch (Exception e) {
logger.error("error: " + e);
}
finally {
try {
if (inFromClient != null) inFromClient.close();
if (outToClient != null) outToClient.close();
if (serverSocket != null) serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}


package com.ndung.socket;

import java.io.IOException;
import java.net.ServerSocket;

public class SocketConnectionServer {
private ServerConfig config;
private SocketServerHandlerFactory handlerFactory;
private boolean stop;
public SocketConnectionServer(ServerConfig config, SocketServerHandlerFactory handlerFactory) {
this.config = config;
this.handlerFactory = handlerFactory;
}
public void start() throws IOException {
stop = false;
final ServerSocket serverSocket = new ServerSocket(config.getPort());
new Thread(new Runnable() {
public void run() {
while (!stop) {
try {
handlerFactory.createHandler(serverSocket.accept()).start();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
public void stop() {
stop = true;
}
}

Create a socket server class named MyServer.java. This class also as a main class for our application. And then we will create a socket client class named MyClient.java. Before that create applicationContext.xml in default package as Spring configuration injection for our main class.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
<bean id="socketConnectionServer" class="com.ndung.socket.SocketConnectionServer">
<constructor-arg>
<ref local="config" />
</constructor-arg>
<constructor-arg>
<ref local="socketServerHandlerFactory" />
</constructor-arg>
</bean>

<bean id="config" class="com.ndung.socket.ServerConfig">
<property name="port">
<value>50000</value>
</property>
</bean>

<bean id="socketServerHandlerFactory" class="com.ndung.socket.SocketServerHandlerFactory">
<constructor-arg>
<ref local="messageHandler" />
</constructor-arg>
</bean>

<bean id="messageHandler" class="com.ndung.iso8583.MessageHandler">
</bean>

</beans>


package com.ndung.socket;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyServer {

public static void main(String[] args) throws IOException {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
SocketConnectionServer server = (SocketConnectionServer) ctx.getBean("socketConnectionServer");
server.start();
}
}


package com.ndung.socket;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import org.apache.log4j.Logger;

public class MyClient {
private final int MY_PORT=50000;
private final String TargetHost = "localhost";
private final String QUIT = "QUIT";
private Logger logger = Logger.getLogger( getClass() );
public MyClient() {
try {
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
Socket clientSocket = new Socket(TargetHost, MY_PORT);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
logger.info(inFromServer.readLine());
boolean isQuit = false;
while (!isQuit) {
System.out.print("Your data : ");
String cmd = inFromUser.readLine();
cmd = cmd.toUpperCase();
if (cmd.equals(QUIT)) {
isQuit = true;
}
outToServer.writeBytes(cmd + "\n");
String message = inFromServer.readLine();
while (message!=null){
logger.info("From Server: " + message);
message = inFromServer.readLine();
}
}
outToServer.close();
inFromServer.close();
clientSocket.close();
}
catch (IOException ioe) {
logger.error("Error:" + ioe);
}
catch (Exception e) {
logger.error("Error:" + e);
}
}
public static void main(String[] args) {
new MyClient();
}
}

Run our application first. It means our main class (MyServer.java) will be run first. And then run client as much that we want. It means MyClient.java will be run twice or more. And then in one of our client application console enter an input data. It means a String of ISO message. As example:
0210723A00010A808400185936001410010999990110000000100000001007021533000001191533
10061007065656561006090102240000000901360020100236C0102240000000
Look in both of our application console either MyServer or MyClient. What do you see?
Btw, Happy Eid Mubarak...

Read More..

Thursday, September 18, 2008

Quartz Scheduler First Impression

Quartz Scheduler is used to make a scheduling job. In this post we will make a scheduler to generate daily report for persons report that have we made before for each one minute. Here we start. Download first Quartz library and copy it into spring lib folder. In package com.ndung.service create two interfaces named EODManager.java and Executable.java.


package com.ndung.service;

public interface EODManager {
void executeEOD();
}

package com.ndung.service;

public interface Executable {
void execute() throws Exception;
}

In package com.ndung.service.impl add a class named EODManagerImpl.java

package com.ndung.service.impl;

import java.util.List;
import com.ndung.service.EODManager;
import com.ndung.service.Executable;

public class EODManagerImpl implements EODManager {
private List<Executable> executables;
public void setExecutables(List<Executable> executables) {
this.executables = executables;
}
public void executeEOD() {
for (Executable executable : executables) {
try { executable.execute(); }
catch (Exception e) { e.printStackTrace(); }
}
}
}


Edit PersonManager.java and PersonManagerImpl.java like belows.

public interface PersonManager extends Manager, Executable{
...
public void generateDailyReport();
}

PersonManagerImpl.java

public void generateDailyReport() {
File dirPath = new File("report");
if (!dirPath.exists()) {
dirPath.mkdirs();
}
File filePath = new File(dirPath+"/PersonReport.pdf");
Map<String, Object> mapReport = new HashMap<String, Object>();
mapReport.put("title", "Persons Report");
mapReport.put("date", new Date());
ReportUtil.generateReport("PersonsReport.jrxml", filePath.getAbsolutePath(),
dao.getPersons(null), mapReport, "pdf");
}
public void execute() throws Exception {
generateDailyReport();
}

Add a bean in applicationContext-service.xml for eodManager.

<bean id="eodManager" class="com.ndung.service.impl.EODManagerImpl">
<property name="executables">
<list>
<ref bean="personManager" />
</list>
</property>
</bean>

In folder web/WEB-INF create applicationContext file named applicationContext-schedule.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref local="cronTrigger" />
</list>
</property>
</bean>

<bean id="cronTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="methodInvokingJobDetail" />
</property>
<property name="cronExpression">
<value>0 0/1 * * * ?</value>
</property>
</bean>

<bean id="methodInvokingJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="eodManager" />
</property>
<property name="targetMethod">
<value>executeEOD</value>
</property>
</bean>
</beans>

Run our application and check out if there a file in report/PersonReport.pdf in our computer.

Read More..

Wednesday, September 17, 2008

JasperReports First Impression

In previous post we have made Person model (POJO) and DAO also manager to perform CRUD on person object. Now we will generate report of person list by using JasperReports and IReport. We use IReport to make .jrxml file that needed by JasperReports. This tool is so powerful because easy to use and GUI based. Here we start. Download first JasperReports libraries and IReport application. Copy JasperReports libraries folder into AppfuseExample lib folder. Edit lib.properties file.


#
#Jasper
#
jasper.version=1.2.0
jasper.dir=${lib.dir}/jasperreports-${jasper.version}
jasper.jar=${jasper.dir}/jasperreports-1.2.0.jar

Create a class to generate report in package com.ndung.util named ReportUtil.java.

package com.ndung.util;

import java.io.*;
import java.util.*;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.*;
import net.sf.jasperreports.engine.util.JRLoader;

public class ReportUtil {
public static void generateReport(String templateFilename, String outputFilename, List data,
Map<String, Object> reportParameters, String fileType) {
try {
OutputStream os = new FileOutputStream(outputFilename);
generateReport(templateFilename, os, data, reportParameters, fileType);
os.close();
} catch (IOException e) { e.printStackTrace(); }
}
public static void generateReport(String templateFilename, OutputStream os, List data,
Map<String, Object> reportParameters, String fileType) {
String reportFileName = ReportUtil.class.getResource("/" + templateFilename).getFile();
if(reportParameters == null)
reportParameters = new HashMap<String, Object>();
try {
JasperPrint jasperPrint;
JasperReport jasperReport = getCompiledReport(reportFileName);
jasperPrint = JasperFillManager.fillReport(jasperReport, reportParameters,
new JRBeanCollectionDataSource(data));
JRExporter exporter = null;
if (fileType.equals("txt")) exporter = new JRTextExporter();
else if (fileType.equals("csv")) exporter = new JRCsvExporter();
else if (fileType.equals("xls")) exporter = new JRXlsExporter();
else exporter = new JRPdfExporter();
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, os);
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
exporter.exportReport();
} catch (Exception e) { e.printStackTrace(); } }
private static JasperReport getCompiledReport(String reportFileName) throws JRException {
File reportFile = new File(reportFileName.replace("jrxml", "jasper"));
if (!reportFile.exists())
JasperCompileManager.compileReportToFile(reportFileName);
return (JasperReport) JRLoader.loadObject(reportFile.getPath());
}
}

Now open IReport to make jrxml file. Click File -> New Document. Fill report name with PersonsReport.jrxml. Click Tools -> Classpath. Add jar/folder where our classes built. As example: /home/ndung/workspace/AppfuseExample/bin. Click Datasource -> Report Query, in tab JavaBean Datasource, fill class name with com.ndung.model.Person and click Read javabeans attributes. If your classpath right, it will read attributes of person. Create document like picture below by dragging fields or variables or parameters in right panel (library). Save this file into folder src/web. Try to compile this file by clicking button compile. If there is no error, it will be compiled successfully. If this file has been compiled it will generate file .jasper. Check out PersonsReport.jasper in your computer folder.


We will add a page special that can be called from menu directly. In package com.ndung.webapp.action create a class named PersonReport.java. In folder web/pages create two files named personReport.html and personReport.page.

package com.ndung.webapp.action;

import java.io.*;
import java.util.*;
import java.util.zip.*;
import com.ndung.model.Person;
import com.ndung.service.Manager;
import com.ndung.util.ReportUtil;

public abstract class PersonReport extends BasePage{
public abstract Manager getManager();
public void generate() throws IOException{
List persons = getManager().getObjects(Person.class);
OutputStream os = getResponse().getOutputStream();
getResponse().addHeader( "Content-Disposition", "attachment; filename=report.zip");
getResponse().setContentType( "application/zip" ) ;
os = new ZipOutputStream( os );
String templateFilename = "PersonsReport.jrxml";
Map<String, Object> mapReport = new HashMap<String, Object>();
mapReport.put("title", "Persons Report"); mapReport.put("date", new Date());
((ZipOutputStream)os).putNextEntry( new ZipEntry("PersonsReport.pdf" ) ) ;
ReportUtil.generateReport(templateFilename, os, persons, mapReport, "pdf");
((ZipOutputStream)os).closeEntry() ;
os.flush();
os.close();
}
}


<span jwcid="@ShowValidationError" delegate="ognl:beans.delegate"/>
<span jwcid="@ShowMessage"/>
<form jwcid="form">
<input type="submit" class="button" jwcid="@Submit" value="message:button.generate" id="save" action="listener:generate"/>
</form>


<?xml version="1.0"?>
<!DOCTYPE page-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 4.0//EN"
"http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
<page-specification class="com.ndung.webapp.action.PersonReport">
<inject property="request" object="service:tapestry.globals.HttpServletRequest"/>
<inject property="response" object="service:tapestry.globals.HttpServletResponse"/>
<inject property="manager" type="spring" object="manager"/>
<bean name="delegate" class="org.apache.tapestry.valid.ValidationDelegate"/>
<component id="form" type="Form">
<binding name="delegate" value="ognl:beans.delegate"/>
<binding name="clientValidationEnabled" value="true"/>
</component>
</page-specification>

In tapestry application add mapping file for .page and .html.

<page name="personReport" specification-path="pages/personReport.page"/>

Edit ApplicationResources.properties and build.xml like belows.

menu.person=Person
menu.person.list=Person List
menu.person.report=Person Report
personreport.heading=Person Report
personreport.title=Person Report
button.generate=Generate


<target name="package-web" ...>
...
<copy todir="${build.dir}/web/classes">
<fileset dir="src/web">
...
<include name="**/*.jrxml"/>
<include name="**/*.jasper"/>
</fileset>
</copy>
...
<war destfile="${webapp.dist}/${webapp.war}" duplicate="preserve" ,,,>
...
<lib dir="${jasper.dir}" includes="*.jar"/>
</war>
</target>

Last, add menu for this feature.

insert into menu(id,name,url,parent) values(10,"menu.person",null,null);
insert into menu(id,name,url,parent) values(11,"menu.person.list","persons.html",10);
insert into menu(id,name,url,parent) values(12,"menu.person.report","personsReport.html",10);
insert into role_menu(role_id,menu_id) values(1,10);
insert into role_menu(role_id,menu_id) values(2,10);
insert into role_menu(role_id,menu_id) values(1,11);
insert into role_menu(role_id,menu_id) values(2,11);
insert into role_menu(role_id,menu_id) values(1,12);
insert into role_menu(role_id,menu_id) values(2,12);

Read More..

Tuesday, September 16, 2008

Performing CRUD on Object in AppFuse

We have created a model named Person before. Besides using this, we also can use Middlegen that have been integrated in AppGen AppFuse to generate POJOs from database tables. Now, we will add a CRUD (create, retrieve, update, delete) application for Person. Firstly, we have must to create a new DAO to perform CRUD on the object and then create a new manager for creating Business Facades that talk to the database tier (DAOs) and handle transaction management. The last, we make web presentation to do CRUD on that object. We will use AppFuse AppGen tool that I have talked before to do all of this.

Here, we start. Open terminal and enter extras/appgen directory. Run "ant" (It'll generate all the files that we need. However, we can just grab the ones we need) or "ant install" (to use the generic DAO and manager) or instead ant-install we can use better way, "ant install-detailed" (to general a DAO and Manager specifically for our model object). We will use the last one. After we run this command, We will be prompted to generate from a POJO or a Table. If we choose pojo, the .java file should already exist in our "model" package. Because person POJO has been in our model package, we can use this or we can use this command directly:
ant -Dobject.name=Person -Dappgen.type=pojo.
ant install -Dobject.name=Person -Dappgen.type=pojo.
ant install-detailed -Dobject.name=Person -Dappgen.type=pojo.

But if we choose table, Middlegen will be used to create a POJO from an existing database table. This will generate all the files that needed to test and perform CRUD on an object. We will use this second way, by using Middlegen. Delete first our Person.java in our model package.


Finally, we will be asked to enter an application module or sub-package name. This is an optional feature that will allow us to organize our classes into sub-packages. For example, for a POJO "model" package of "org.appfuse.foo.model", just enter foo when prompted.

Here are the list of new files or files that have been edited after we refresh our project in Eclipse:
(in src folder)
1. com.ndung.Constant (edit)
2. com.ndung.model.Person
3. com.ndung.dao.PersonDao
4. com.ndung.dao.PersonDaoHibernate
5. applicationContext-hibernate.xml (edit)
Note: In this file, we also must have to add "com/ndung/model/Person.hbm.xml" in list of value of mappingResources if there is no before.
6. com.ndung.service.PersonManager
7. com.ndung.service.PersonManagerImpl
8. applicationContext-service.xml (edit)
9. com.ndung.webapp.action.PersonForm
10. com.ndung.webapp.action.PersonList

(in test folder)
1. com.ndung.dao.PersonDaoTest
2. com.ndung.dao.PersonManagerTest
3. com.ndung.webapp.action.PersonFormTest
4. com.ndung.webapp.action.PersonListTest

(in web folder)
1. pages/web/personForm.html
2. pages/web/personForm.page
3. pages/web/persons.html
4. pages/web/persons.page
5. WEB-INF/tapestry.application (edit)

Last, we add a new menu in our database menu table. Also we have to add roles and that menu in role_menu table.
insert into menu(id,name,url,parent) values(10,"menu.person","persons.html",null);
insert into role_menu(role_id,menu_id) values(1,10);
insert into role_menu(role_id,menu_id) values(2,10);

Build our project through ANT (by run "ant deploy" command in our project package). Here is a screenshot of http://localhost:8080/AppfuseExample after our engine (Tomcat) started and log in as mraible.


UPDATE:
I'm trying syntax highlighter and modified by FaziBear for Blogspot. We will add search feature in this application. Edit files below by adding these codes.

PersonDao.java


public List findPersons(Person param);

PersonDaoHibernate.java

public List findPersons(Person param) {
DetachedCriteria criteria = DetachedCriteria.forClass(Person.class);
if (param.getId()!=null){
criteria.add(Restrictions.eq("id", param.getId()));
}
if (param.getFirstName()!=null){
criteria.add(Restrictions.eq("firstName", param.getFirstName()));
}
if (param.getLastName()!=null){
criteria.add(Restrictions.eq("lastName", param.getLastName()));
}
criteria.addOrder(Order.desc("id"));
return getHibernateTemplate().findByCriteria(criteria);
}

PersonManager.java

public List findPersons(Person param);

PersonManagerImpl.java

public List findPersons(Person param) {
return dao.findPersons(param);
}

PersonList.java

public abstract class PersonList extends BasePage implements PageBeginRenderListener{
public abstract PersonManager getPersonManager();
public abstract List getPersons();
public abstract void setPersons(List persons);
public abstract Person getParam();
public abstract void setParam(Person param);
public void pageBeginRender(PageEvent event) {
search(event.getRequestCycle());
}
public void search(IRequestCycle cycle) {
if (getParam() == null) setParam(new Person());
List personList = getPersonManager().findPersons(getParam());
PersonList nextPage = (PersonList) cycle.getPage();
nextPage.setPersons(personList);
cycle.activate(nextPage);
}
...

persons.html

<form jwcid="personForm@Form">
<table class="form">
<tr>
<td><label><span key="personList.namesearched"/></label></td>
<td>
<input jwcid="@TextField" value="ognl:param.firstName" />
</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" class="button" jwcid="@Submit" value="message:button.search" id="search"
listener="ognl:listeners.search"/>
</td>
</tr>
</table>
...
</form>

ApplicationResources.properties

# -- person list page--
menu.person=Person List
personList.namesearched=Person First Name


Here is a screenshot:

Read More..

Monday, September 15, 2008

Hibernate XDoclet Class From Table Generator

Still remember Hibernate XDoclet? In this post, we will create an AppGen in AppFuse. Imagine if we have a hundred of columns in our table in database and we have must to write a model of that class, it's fields, it's getter and setter one by one. So, here we start. In this example, our table (person) just have 3 columns.


Create folder util in src folder. In Eclipse, create source folder that refer to src/util. Create a package in that source folder named com.ndung.gen. For the first step, we must prepare our model template for class.template, field.template, getter.template, and also setter.template. We also have to prepare our jdbc properties to connect to our database.

class.template


field.template


getter.template


setter.template


jdbc.properties

After that, we create two classes named TableInspector.java and ClassGenerator.java. TableInspector is used to inspect data type in each columns in table and map it in to Java class type. In another hand, ClassGenerator is used to write a Java model class file based on our template above.

TableInspector.java


ClassGenerator.java

Now, we create a main Java class named HibernateXDocletClassFromTableGenerator.java.


Run that class above and refresh our project. Look in folder src/dao in package com.ndung.model. There is a model class named Person.java. We must change XDoclet attribute for id from hibernate.property to become hibernate.id.

Person.java

Read More..

Thursday, September 11, 2008

Struts-Menu First Impression

We will talk about Struts-Menu tag library. It's demo can be seen in here and it's library can be downloaded in here. We will integrate it in AppFuse. Before we start, you must do this first. We will try build a simple menu from a database table. It's demo can be seen in here. In our that project (AppfuseExample), by default we can add menu and menu item in menu-config.xml. But how we can add dynamic driven menu from database? Okay, we will start here. There are 3 tables by default in our database (NDUNGDB). They are app_user, role, and user_role. We will add 2 tables more for our configuration menu. They are menu and role_menu. Table menu will store menus and table role_menu will store which menus can be accessed by which roles. Table menu will have 4 columns they are id, name, url, and parent. In other hand role_menu table will have 2 columns. They are role_id and menu_id.

DDL SQL file for table menu and role_menu

Edit table menu and role_menu. Add fields for them. Here is my menu and role_menu table based on default configuration of AppFuse. I'm using MySQL Query Browser.

menu table.


role_menu table.

We will add persistence model for menu by mapping table menu and edit role model in addition role_menu mapping table. In package com.ndung.model, add file Menu.java and edit Role.java by adding attribute menus.

Menu.java


Role.java (edit)

In applicationContext-hibernate.xml add mapping model for menu. Add this line in mapping resources.

applicationContext-hibernate.xml (edit)

We will add a filter in package com.ndung.webapp.filter named AuthenticationProcessingFilter by extend AcegiSecurity default filter. This filter is used to store all menus (menu names and it's url) from database and all roles that can access those menus in repository. Then, edit security.xml by adding this filter.

AuthenticationProcessingFilter.java


security.xml (edit)

We will use ListMenu. Add mapping menu in menu-config.xml. Add this line in displayers.

menu-config.xml (edit)

In folder web/pages add jsp file named menu.jsp (the other menu.jsp file is in folder web/common) and in folder web/decorators/ backup our default.jsp and edit it like this. Also you must have to need menuExpandable.css and menuExpandable.js. Place menuExpandable.css in folder web/styles and menuExpandable.js in folder web/scripts.

menu.jsp


default.jsp

Add these lines in ApplicationResources.properties.

ApplicationResources.properties (edit)

Here is some screenshot after we login as mraible. We must add a default css for a better view for sure.


Read More..

Monday, September 01, 2008

AppFuse First Impression (An Introduction to MVC Design Pattern)

Now, we have learned about Tapestry, Hibernate, and Spring. So, let me introduce a MVC architecture. An architecture such as MVC is a design pattern that describes a recurring problem and its solution that used 3 main components. MVC, They are Model (business logic goes here), View (presentation logic goes here), and Controller (application logic goes here). One of MVC framework is Brick/ AppFuse Framework. By default, AppFuse use Hibernate framework as Model (object persisting framework), Tapestry framework as View (web presentation), and Spring framework as Controller. So, here it is...

All that we need are AppFuse framework, Apache Ant, MySQL as database, Apache Tomcat as application server, Eclipse as IDE and JUnit as testing tools. Extract Apache Ant in a specific location, as example in /home/ndung/Java/ant/apache-ant-1.7.0. Configure our environment variables.
~$ sudo gedit /etc/bash.bashrc

Add these lines in that file:
export ANT_HOME=/home/ndung/Java/ant/apache-ant-1.7.0
export PATH=$PATH:$ANT_HOME/bin


To configure Apache Tomcat and Eclipse read this. Extract Junit in specific folder and copy junit-x.x.jar into Apache Ant libraries (apache-ant-1.7.0/lib). Extract AppFuse in our eclipse workspace as example /home/ndung/workspace/appfuse. Open properties.xml and edit tomcat properties (line 37-40) based on our tomcat configuration mainly in user name and password. Also edit our database properties (line 43-59) based on our MySQL or our other database configuration mainly in user name and password. Open terminal and run:
~$ ant new


After that enter our project workspace folder. Run setup and test-all.
~$ cd /home/ndung/workspace/AppfuseExample
~$ ant setup test-all


Finish! Now start our tomcat. We will start it manually by using terminal. Enter Tomcat installation bin folder.
~$ cd /opt/apache-tomcat-5.5.26/bin

Add the execute permission to all of the .sh files in the $CATALINA_HOME/bin directory.
~$ sudo chmod u+x startup.sh
~$ sudo chmod u+x catalina.sh
~$ sudo chmod u+x setclasspath.sh
~$ sudo chmod u+x shutdown.sh


Start our engine (tomcat) by using this command:
~$ ./startup.sh

Now, point our browser into http://localhost:8080/AppfuseExample. Use our tomcat user name and password to log in as user, as example in my tomcat configuration, user name: tomcat; password: tomcat. To log in as administrator use mraible as user name and tomcat as password.
Here is some screen shot:


Don't forget to shut down our engine:
~$ ./shutdown.sh

Now, how to edit this project by using IDE. Open our Eclipse. Click File -> Import. Select Existing Projects into workspace under General item as an import source. Click next. Select our eclipse workspace (example:/home/ndung/workspace) as root directory. Check AppfuseExample in Projects then click Finish. Now, we can easily to add whatever in our project. In the next posts we will add other feature in this our project.

Read More..

Wednesday, August 20, 2008

Spring-Hibernate Hands On

Now, lets talk about combining hibernate persistence framework and Spring framework. As you see from previous post, that Spring JDBC still use SQL query to access data objects in database. All that you need are:
1. Eclipse as IDE
2. MySQL 5 as Database
We also need other libraries such as:
1. Spring Framework
2. Hibernate-3.*
3. MySQL-connector-java-5.*
4. Jakarta-commons
5. X-Doclet-1.*

Create a java project in Eclipse named SpringHibernateExample. Create a new folder named lib. It is used to place our libraries. Move all libraries above to folder lib. So in the lib folder, there are 5 folders inside. Also add a properties file in the lib folder named lib.properties. This is an example, my lib.properties. It show my libraries configuration. Make it in your own. Also configure build path our project into these libraries.

lib.properties

In source folder make java package named com.ndung.model and com.ndung.main. We will place our POJOs in com.ndung.model and main file in com.ndung.main. Create java classes in com.ndung.model named User.java and UserDaoHibernate.java as data access object to database. Also make a xml file named myconfig.xml and a properties file named hibernate.properties in our project source folder. In other side, create java main class named Main.java in com.ndung.main.

User.java


UserDaoHibernate.java


myconfig.xml


hibernate.properties


Main.java

As usually we will run our project by using Ant. Create two xml files named properties.xml and build.xml.

properties.xml


build.xml

Read More..

Tuesday, August 19, 2008

Spring JDBC First Impression

In this example, all that you need are:
1. Eclipse as IDE
2. MySQL 5 as Database
We also need other libraries such as:
1. Spring Framework
2. MySQL-connector-java-5.*
3. Jakarta-commons

Create a java project in Eclipse named SpringJdbcExample. Create a new folder named lib. It is used to place our libraries. Move all libraries above to folder lib. So in the lib folder, there are 3 folders inside. Also add a properties file in the lib folder named lib.properties. This is an example, my lib.properties. It show my libraries configuration. Make it in your own. Also configure build path our project into these libraries.

lib.properties

In source folder make java package named com.ndung.model and com.ndung.main. Create java classes in com.ndung.model named User.java as entity, UserRowMapper.java as mapping entity file to database, and UserDaoSpringJdbc.java as data access object to database. Also make a xml file named dbConnection.xml that used to configure database connection. In other side, create main java class named Main.java in com.ndung.main.

User.java


UserRowMapper.java


UserDaoSpringJdbc.java


dbConnection.xml


Main.java

As usually we will run this project by using Ant. Make a xml file named build.xml in this project.

build.xml

Read More..

Monday, August 18, 2008

IOC (Inversion of Control) - An Introduction to Spring

As usually we need Eclipse as IDE. We also need other libraries such as Spring Framework libraries and Jakarta Commons libraries especially commons-logging. Create a project named IoCDemo. In this project create a new folder named lib and move all our libraries into this folder. Create a library properties file, lib.properties. This is my library configuration properties. Make it in your own. Also configure build path our project into these libraries.

lib.properties

Then in source folder make two packages named com.ndung.myspring and com.ndung.main. In com.ndung.myspring create a java interface named Greeting.java and a java class named GreetingImpl.java. In source folder create a xml file as configuration of our spring injection named Hello.xml and in package com.ndung.main create a main java class named Main.java.

Greeting.java


GreetingImpl.java


Hello.xml


Main.java

We will run this project by using Ant. Create a xml file in this project named build.xml and run this project.

build.xml

Read More..