Tuesday, September 07, 2010

DSLs

Somewhere in the DSL world

Thursday, February 25, 2010

Domain Driven Design

Reading domain driven design... A book which increase your passion for software development.

Tuesday, July 29, 2008

Installing Sata Driver After Installing XP

This post worked excellent for me.

Monday, July 28, 2008

MessageDialogWithToggle

If you want add some confirmation dialogs to your rcp project, you should look at MessageDialogWithToggle jface component. By using this component, you can save user's preferences for the next time your window open. So user can choose not to being prompted anymore. You can do a message dialog like Eclipse's Confirm Exit message dialog which contains a checkbox ( "Always Exit Without Prompt"). Or simply you can use this component to add a checkbox to MessageDialog component.

MessageDialogWithToggle source

Sunday, July 27, 2008

A tutorial for Spring,Hibernate,JSF,Richfaces

Post is moved to here

Tuesday, July 22, 2008

Sample Spring,Hibernate,JSF,Richfaces Application

MOTIVATION

In this basic tutorial, I tried to show how spring, hibernate, jsf, richfaces can be used together as a working example. Sources can be downloaded at the end of page.

I am working about 3 days to configure Spring,Hibernate,JSF,Facelets,Richfaces all in one as a maven project with maven jetty plugin. Now it s time to share this configuration as a working example.
First lets look at root pom.xml
ROOT pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>blogspot.sezera.exampleproject</groupId>
<artifactId>exampleproject</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>exampleproject</name>
<url>http://maven.apache.org</url>
<dependencies/>
<modules>
<module>exampleproject.core</module>
<module>exampleproject.web</module>
</modules>
</project>

We have 2 project. One of them is core and the other is web. Nothing is interesting here.

Core Project

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project>
<parent>
<artifactId>exampleproject</artifactId>
<groupId>blogspot.sezera.exampleproject</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>blogspot.sezera.exampleproject.core</groupId>
<artifactId>exampleproject.core</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>Exampleproject Core</name>
<url>http://maven.apache.org</url>
<build>
<resources>
<resource>
<directory>target/generated-resources</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.6.ga</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.3.1.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-tools</artifactId>
<version>3.2.0.ga</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.5</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Repository for Maven</name>
<url>http://download.java.net/maven/2</url>
<layout>default</layout>
</repository>
</repositories>
</project>

java.net repository needed for maven to download Richfaces jars. Other jars will be downloaded from maven.org maven 2 repository.
  • dao-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- DATASOURCE DEFINITON-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/exampleproject" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<!-- HIBERNATE CONFIGURATION -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>blogspot.sezera.exampleproject.domain.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.use_outer_join">true</prop>
<prop key="hibernate.max_fetch_depth">1</prop>
<prop key="hibernate.jdbc.batch_size">0</prop>
<prop key="hibernate.default_schema">exampleproject</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
</beans>

blogspot.sezera.exampleproject.domain.User class is entity class and it will be persisted to mysql database with hibernate. Because User class using hibernate annotation , instead of xml mapping files, Spring's AnnotationSessionFactoryBean is used for building Session Factory bean. A datasource is defined and defined as a property to sessionFactory bean.
User class is given as a parameter to annotatedClass list property. Here you must add your annotated classes which will be persisted to database.
And another property is hibernateProperties which is actually arguments to hibernate. Here "default schema" is defined as "exampleproject" and hibernate.hbm2ddl.auto set to "update". It means hibernate will update database schema reading hibernate annotated entity classes like "User" class. There is no hbm.xml map files but its names stay same, actually everything done with annotation. So at first, you need to create an empty database schema (create database exampleproject) in mysql database and hibernate will take care of rest.
Actually we can move hibernateProperties property of sessionFactory bean to a file which is named "hibernate.properties" but to keep space minimum it is written inside of dao-context.xml.
  • User.java
package blogspot.sezera.exampleproject.domain;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="User")
public class User implements Serializable{

private Long id;

private String username;
private String password;

@Id
@GeneratedValue
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

}

User class is a basic entity with email, password fields and accessor methods. id attribute is defined as unique identifier for User entity by @Id annotation. Accessor for id is getId() method. Here ids are generating and managing by hibernate. @GeneratedValue annotation can be used for defining id generation strategy but we leave it default here.
  • main-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

<import resource="dao-Context.xml"/>

<!--SERVICE BEAN DEFINITIONS-->
<bean id="userService"
class="blogspot.sezera.exampleproject.service.impl.UserServiceImpl">
<constructor-arg ref="sessionFactory"></constructor-arg>
</bean>

<!--TRANSACTIAN MANAGEMENT-->
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true" />
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" />
</tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the userManagementService interface -->
<aop:config>
<aop:pointcut id="managementServiceOperation"
expression="execution(* blogspot.sezera.exampleproject.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="managementServiceOperation" />
</aop:config>

</beans>

main-Context.xml corresponds to Spring's applications classic application-context.xml but we moved entity definition, database and hibernate configurations to dao-Context.xml so we start with importing it.
Every class in service layer has its own interface so UserService interface defined with single createUser method. userService bean is defined with concrete UserServiceImpl class and sessionFactory which is defined in dao-Context.xml before is injected with constructor injection.
Hibernate needs transactions.Without transactions you can't write anything to database.Thanks to aspects transaction behaviour of exampleproject defined easily.A transaction manager bean is defined and sessionFactory instance is given via setter injection.Secondly an advice is defined which says all methods starts with get(like getUserName ...) in a transaction is readonly and other metods are in default transaction behaviour. Critical point is defining where to apply advice in short pointcuts. With aspect expression we define pointcuts for every class under blogspot.sezera.exampleproject.core.service package which is actually service layer.
  • UserService.java
package blogspot.sezera.exampleproject.service;
public interface UserService {

void createUser(String username,String password);

}
  • UserServiceImpl.java
package blogspot.sezera.exampleproject.service.impl;

import org.hibernate.SessionFactory;

import blogspot.sezera.exampleproject.dao.GenericDaoImpl;
import blogspot.sezera.exampleproject.domain.User;
import blogspot.sezera.exampleproject.service.UserService;

public class UserServiceImpl implements UserService{

private SessionFactory m_sessionFactory;
private GenericDaoImpl<User,Long> userDao;

public UserServiceImpl(SessionFactory sessionFactory) {
m_sessionFactory = sessionFactory;
userDao = new GenericDaoImpl<User, Long>(m_sessionFactory){};
}

public void createUser(String username, String password) {
User user = null;
if(username!=null){
user = new User();
user.setUsername(username);
user.setPassword(password);
userDao.makePersistent(user);
}
}
}


Here Dao pattern is used with generics support. A GenericDaoImpl instance is created for User entity and persisted with makePersistent method which is actually a single line: getSession().saveOrUpdate(entity).
  • GenericDao.java
package blogspot.sezera.exampleproject.dao;
package blogspot.sezera.exampleproject.dao;

import java.io.Serializable;

public interface GenericDao<T extends Serializable,ID extends Serializable>{
T makePersistent(T entity);
}
  • GenericDaoImpl.java
package blogspot.sezera.exampleproject.dao;

import java.io.Serializable;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

public abstract class GenericDaoImpl<T extends Serializable,ID extends Serializable> implements
GenericDao<T,ID>{

private SessionFactory sessionFactory;

public GenericDaoImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

public T makePersistent(T entity) {
getSession().saveOrUpdate(entity);
return entity;
}

protected Session getSession() {
return sessionFactory.getCurrentSession();
}
}

Now we have everything in core side to create a User. So moving to web project.

Web project
  • pom.xml

<?xml version="1.0"?>
<project>
<parent>
<artifactId>exampleproject</artifactId>
<groupId>blogspot.sezera.exampleproject</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>blogspot.sezera.exampleproject.web</groupId>
<artifactId>exampleproject.web</artifactId>
<packaging>war</packaging>
<name>exampleproject.web Maven Webapp</name>
<version>1.0-SNAPSHOT</version>
<url>http://maven.apache.org</url>
<build>
<finalName>exampleproject.web</finalName>
<!--MAVEN JETTY PLUGIN-->
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.10</version>
<configuration>
<scanIntervalSeconds>3</scanIntervalSeconds>
</configuration>

</plugin>
</plugins>

</build>
<dependencies>
<dependency>
<groupId>blogspot.sezera.exampleproject.core</groupId>
<artifactId>exampleproject.core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>1.2_02</version>
</dependency>

<dependency>
<groupId>com.sun.facelets</groupId>
<artifactId>jsf-facelets</artifactId>
<version>1.1.11</version>
</dependency>

<dependency>
<groupId>javax.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>1.2-b19</version>
</dependency>

<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>

<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
</dependency>

<dependency>
<groupId>org.richfaces.ui</groupId>
<artifactId>richfaces-ui</artifactId>
<version>3.1.0</version>
</dependency>

</dependencies>
<repositories>
<repository>
<id>repository.jboss.com</id>
<name>Jboss Repository for Maven</name>
<url>http://repository.jboss.com/maven2/</url>
<layout>default</layout>
</repository>
</repositories>
</project>
  • UserController.java
package blogspot.sezera.exampleproject.controller;

import blogspot.sezera.exampleproject.service.UserService;

public class UserController {

private UserService service;
private String username;
private String password;

public UserController(){

}
public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public void setService(UserService service) {
this.service = service;
}

public void createUser(){
service.createUser(username, password);
}
public UserService getService() {
return service;
}
}
  • EmailValidator.java
package blogspot.sezera.exampleproject.validator;

import java.util.ResourceBundle;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

public class EmailValidator implements Validator{

public void validate(FacesContext arg0, UIComponent arg1, Object arg2)
throws ValidatorException {

String email = arg2.toString();
if(email.contains("@")==false){
//error message
ResourceBundle bundle = ResourceBundle.getBundle("messages",arg0.getCurrentInstance().getViewRoot().getLocale());
FacesMessage msg = new FacesMessage(bundle.getString("emailNotValid"));
throw new ValidatorException(msg);
}

}
}

To validate user email address when creating user I have created a basic EmailValidator. It validates if user email address contains "@". If not a ValidatorException is thrown.
  • messages_en_US.properties

emailNotValid=E-mail is not valid
  • newUser.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<head>
<title>New User</title>
</head>
<body>
<f:view>
<h:form>
<table>
<tr>
<td><h:outputLabel value="UserName "></h:outputLabel></td>
<td><h:inputText id="email" value="#{userController.username}">
<f:validator validatorId="emailValidator" />
<a4j:support event="onkeyup" requestDelay="300" reRender="output"/>
</h:inputText>
</td>
<td>
<h:outputLabel id="output">
<h:message for="email"/>
</h:outputLabel>
</td>
</tr>
<tr>
<td><h:outputLabel value="Password"></h:outputLabel></td>
<td><h:inputSecret value="#{userController.password}"></h:inputSecret><br/></td>
</tr>
</table>
<h:commandButton value="Create User" action="#{userController.createUser}"></h:commandButton>
</h:form>
</f:view>
</body>
</html>

When user started to write his email address, page send an AJAX request to server in every 300 second and EmailValidator executes. If there is an error in user email, page renders an error message right of user email input text area.
  • web.xml
<?xml version="1.0"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>ExampleProject Web</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/main-Context.xml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<context-param>
<param-name>org.richfaces.SKIN</param-name>
<param-value>classic</param-value>
</context-param>
<context-param>
<param-name>org.ajax4jsf.VIEW_HANDLERS</param-name>
<param-value>com.sun.facelets.FaceletViewHandler</param-value>
</context-param>
<filter>
<display-name>RichFaces Filter</display-name>
<filter-name>richfaces</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>richfaces</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.util.IntrospectorCleanupListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
</web-app>
  • faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>

<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">

<application>

<resource-bundle>
<base-name>messages</base-name>
<var>msgs</var>
</resource-bundle>

<locale-config>
<default-locale>en_US</default-locale>
</locale-config>

<variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>

</application>

<validator>
<validator-id>emailValidator</validator-id>
<validator-class>
blogspot.sezera.exampleproject.validator.EmailValidator
</validator-class>
</validator>

<managed-bean>
<managed-bean-name>userController</managed-bean-name>
<managed-bean-class>
blogspot.sezera.exampleproject.controller.UserController
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>service</property-name>
<value>#{userService}</value>
</managed-property>
</managed-bean>

</faces-config>

HOW TO RUN EXAMPLEPROJECT
  • download source codes without jars.
  • mvn clean install under root directory
  • create an empty database named "exampleproject" in mysql
  • Under exampleproject.web execute: mvn jetty:run
  • http://localhost:8080/exampleproject.web/newUser.faces
NOTE:Attention to url extension is .faces NOT .xhtml. It must be same as url-pattern of Faces Servlet Mapping in web.xml.

SCREENSHOT



DOWNLOADS

source codes

pdf version

REFERENCES
AUTHOR

Sezer Akar
Blog

Thursday, June 05, 2008

Shared Configuration In Eclipse

I realized that even if you don't do anything for shared configuration scenario as described eclipse doc,Eclipse can manage multi users by default. You need to be sure that your default configuration folder( which has config.ini inside of it)of your RCP application is read-only to every user except that root. You have 1 installation for your RCP app and every user can execute the same app. By default, when your RCP app can't write to configuration folder, it creates 2 folder inside of user (who executed app) home directory. 1 for workspace settings and the other for .eclipse folder.
.eclipse/your RCP product/configuration/config.ini is created automatically too. If you look inside of it :
osgi.sharedConfiguration.area=file\:configuration/
It basicly has a link to shared configuration area which is by default configuration folder in RCP product installation. So only root can install plug-in s and every user executed RCP app can see new plugs but cant uninstall or disable and install new plugs.