2011년 5월 23일 월요일

JBoss 5.0+Maven2+EJB3 Development

JBoss 5.0 Download

JBoss 5.0 Install 및 실행
1. Download 받은 jboss-5.0.0.GA*.zip 파일 압축을 푼다.
2. {JBOSS_HOME}/bin/run.bat -b 0.0.0.0 명령어로 JBoss를 실행한다.
*JBOSS_HOME : JBoss Install Directory
*run.bat : Window OS, run.sh : unix, linux OS
* -b 0.0.0.0 : JBoss IP을 바인딩하는 옵션으로 이 옵션을 지정하지 않으며 localhost, 127.0.0.1로만 접근이 가능하고 IP로 접근을 할수 가 없다.

MAVEN 2 Install
1. Download 받은 apache-maven-2.x.x-bin.zip 파일 압축을 푼다.
2. 시스템 환경변수에 MAVEN_HOME으로 Maven2가 설치된 디렉토리를 등록해주고 Path에 {MAVEN_HOME}/bin을 추가해준다.

JBoss 5.0 DataSource 설정
1. {JBOSS_HOME}\server\default\deploy 위치에 ***-ds.xml 파일을 생성하고 아래와 같이 DataSource 정보를 입력 한다.
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>OracleDS</jndi-name>
<connection-url>jdbc:oracle:thin:@xxx.xxx.xxx.xxx:1521:{Oracle SID}</connection-url>
<driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
<user-name>{계정 ID}</user-name>
<password>{계정 Password}</password>
<max-pool-size>5</max-pool-size>
<min-pool-size>1</min-pool-size>
</local-tx-datasource>
</datasources>
2. Oracel JDBC 드라이버와 같이 외부 DB 드라이버 라이브러리를 등록하기 위해 {JBOSS_HOME}\server\default\lib 디렉토리에 해당 라이브러리를 복사해 넣는다. 여기서는 "ojdbc.14.jar"을 넣었다.

EJB 3 개발
1. 여기에서 사용되는 Sample EJB는 Eclipse 3.4을 이용하여 개발되었다. Eclipse에서 Maven을 사용하기 위해 추가 Plug-In을 설치한다.
- Maven Integration for Eclipse Update Site : http://m2eclipse.sonatype.org/update
2. Eclipse에서 Maven Project을 생성하고 pom.xml 파일을 아래와 같이 작성한다.
<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>JBOSS_MAVEN_EJB3</groupId>
<artifactId>Sample</artifactId>
<version>0.0.1</version>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<debug>true</debug>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<optimize>false</optimize>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<configuration>
<ejbVersion>3.0</ejbVersion>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>central</id>
<name>Maven Repository Switchboard</name>
<url>http://repo1.maven.org/maven2</url>
</repository>
<repository>
<id>org.jboss</id>
<name>Maven2 JBOSS</name>
<url>http://repository.jboss.org/maven2</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
<id>central</id>
<name>Maven Plugin Repository</name>
<url>http://repo1.maven.org/maven2</url>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>junit-addons-runner</artifactId>
<groupId>junit-addons</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.2.0.ga</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>ejb-api</artifactId>
<version>3.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
* maven-compiler-plugin : Maven Project의 Default Java Compile은 1.4 버전으로 되어 있기 때문에 1.5 이상 버전을 사용하여 Compile 하기 위해서는 이 plugin을 등록해야 한다.
* maven-ejb-plugin : Maven에서 EJB을 사용하거나 Compile하기 위해서는 이 plugin을 등록해야 한다.
* hibernate-entitymanager : JBOSS에서는 EJB 3 Entity Bean을 핸들링하기 위한 JPA 엔진으로 Hibernate을 사용한다.
* ejb-api : Session Bean과 같이 JPA이외의 EJB 라이브러리를 사용하기 위해 이를 등록해준다.

3. Sample EJB (Path : src/main/java)
- MemberEntity.java
package com.naver.blog.inter999.ejb3.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
// 이 POJO Class가 Entity Bean임을 선언하는 Annotation
@Entity
// Mapping 될 Database의 Table Name 지정해주지 않으면 Class이름과 동일한 Table이 생성된다.
@Table(name="SAMPLE_MEMBER")
public class MemberEntity{
private static final long serialVersionUID = 20081215L;

public long getEmpNo() {
return empNo;
}
public void setEmpNo(long empNo) {
this.empNo = empNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLoginId() {
return loginId;
}
public void setLoginId(String loginId) {
this.loginId = loginId;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}

// 해당 프로퍼티가 PK로 사용됨을 지정 하는 Annotation
@Id
// PK 생성 규칙을 어떤 방식으로 할지 지정 Oracle인 경우 SEQUENCE 방식을 사용하는게 일반적이다.
// 옵션으로는 SEQUENCE, AUTO, IDENTITY 가 있다.
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="id_seq")
// Database 어떤 Sequence를 사용하지를 정의 한다. 여기서는 idseq라는 Sequence가 Database에 존재 하고 있어야 한다.
@SequenceGenerator(name="id_seq", sequenceName="idseq", allocationSize=1)
// 프로퍼티와 매핑되는 Table의 컬럼 속성을 지정한다.
@Column(length=8, nullable=false)
// ID로 사용되는 프로퍼티는 Data Type은 int, short, long, String 중 하나의 속성을 가져야 한다.
// Double, float는 사용할 수 없음.
private long empNo;

@Column(length=20)
private String name;

@Column(length=8)
private String loginId;

@Column(length=8)
private String passwd;
@Column(length=50)
private String email;
}
- MeberVO.java
package com.naver.blog.inter999.vo;
import java.io.Serializable;
public class MemberVO implements Serializable {
private static final long serialVersionUID = 20081215L;

private long empNo;
private String name;
private String loginId;
private String passwd;
private String email;

public long getEmpNo() {
return empNo;
}
public void setEmpNo(long empNo) {
this.empNo = empNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLoginId() {
return loginId;
}
public void setLoginId(String loginId) {
this.loginId = loginId;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
클라이언트 뷰에서 사용할 Value Object을 작성한다.

- MemberList.java
package com.naver.blog.inter999.ejb3.session;
import java.util.List;
import com.naver.blog.inter999.vo.MemberVO;
public interface MemberList {
public MemberVO getMember(long empNo);

public List<MemberVO> getMemberList();

public void modifyMember(MemberVO member);

public void deleteMember(long empNo);

public void insert(MemberVO member);
}

- MemberListBean.java
package com.naver.blog.inter999.ejb3.session;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import com.naver.blog.inter999.ejb3.entity.MemberEntity;
import com.naver.blog.inter999.vo.MemberVO;
// EJB Session Bean 임을 선언하는 Annotation
@Stateless
// Remote Session Bean이며 Remote Interface로 MemberList.class을 사용함을 지정
@Remote(MemberList.class)
public class MemberListBean implements MemberList {
// EntityManager가 사용할 Persistence을 지정한다. Persistence 설정은 persistence.xml 파일에 등록되어 있다.
@PersistenceContext(unitName="DefaultPersistence")
protected EntityManager manager;

@Override
public void deleteMember(long empNo) {
MemberEntity member = manager.find(MemberEntity.class, empNo);
if(member != null)
manager.remove(member);
}
@Override
public MemberVO getMember(long empNo) {
MemberEntity member = manager.find(MemberEntity.class, empNo);
if(member != null) {
return entityToVo(member);
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public List<MemberVO> getMemberList() {
List<MemberEntity> memberList = manager.createQuery("from "+MemberEntity.class.getName()).getResultList();
List<MemberVO> memberVoList = new ArrayList<MemberVO>();

for(MemberEntity entity : memberList) {
memberVoList.add(entityToVo(entity));
}

return memberVoList;
}
@Override
public void modifyMember(MemberVO member) {
MemberEntity entity = manager.find(MemberEntity.class, member.getEmpNo());
entity.setEmail(member.getEmail());
entity.setLoginId(member.getLoginId());
entity.setName(member.getName());
entity.setPasswd(member.getPasswd());
manager.merge(entity);
}

private MemberVO entityToVo(MemberEntity entity) {
MemberVO vo = new MemberVO();
vo.setEmpNo(entity.getEmpNo());
vo.setEmail(entity.getEmail());
vo.setLoginId(entity.getLoginId());
vo.setName(entity.getName());
vo.setPasswd(entity.getPasswd());
return vo;
}

private MemberEntity voToEntity(MemberVO vo) {
MemberEntity entity = new MemberEntity();
entity.setEmail(vo.getEmail());
entity.setLoginId(vo.getLoginId());
entity.setName(vo.getName());
entity.setPasswd(vo.getPasswd());
return entity;
}
@Override
public void insert(MemberVO member) {
manager.persist(voToEntity(member));
}
}

4. Persistence 설정(Path : src/main/resource/META-INF)
<persistence-unit name="DefaultPersistence">
<jta-data-source>java:/OracleDS</jta-data-source>
<properties>
<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.JBossTransactionManagerLookup" />
<property name="hibernate.connection.release_mode" value="after_statement" />
<property name="hibernate.transaction.flush_before_completion"
value="false" />
<property name="hibernate.transaction.auto_close_session"
value="false" />
<property name="hibernate.query.factory_class"
value="org.hibernate.hql.ast.ASTQueryTranslatorFactory" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider" />
<property name="hibernate.jndi.java.naming.factory.initial"
value="org.jnp.interfaces.NamingContextFactory" />
<property name="hibernate.jndi.java.naming.factory.url.pkgs"
value="org.jboss.naming:org.jnp.interfaces" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle9Dialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.max_fetch_depth" value="0" />
</properties>
</persistence-unit>
</persistence>
- Persistence Unit Name을 "DefaultPersistence"로 지정하며 이 이름은 MemberListBean.java에서 "@PersistenceContext"에서 사용된다.
- jta-data-source는 JBOSS에 설정된 DataSource의 JNDI Name을 지정해준다.
- property 항목은 JPA엔진으로 사용되는 Hibernate의 설정을 등록하게 되어 있으며 여기에 설정 되지 않은 값들은 {JBOSS_HOME}/server/default/deployers/ejb3.deployer/META-INF/persistence.properties에 있는 값을 Default로 사용하게 된다.
Sample Package 및 Deploy
- pom.xml 파일이 위치하는 곳에서 "mvn package" 명령어를 실행하여 Sample-0.0.1.jar 파일을 생성한다.
- 생성된 Sample-0.0.1.jar 파일을 {JBOSS_HOME}\server\default\deploy 위치에 복사해 넣는다.
- JBOSS 실행 콘솔 창에 아래와 같은 로그가 출력되면 정상적으로 EJB3 모듈이 Deploy된것이다.
14:18:01,560 INFO [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
MemberListBean/remote - EJB3.x Default Remote Business Interface
MemberListBean/remote-com.naver.blog.inter999.ejb3.session.MemberList - EJB3.x Remote Business Interface

EJB3 Lookup
InitialContext ctx = new InitialContext();
MemberList memberList = (MemberList)ctx.lookup("MemberListBean/remote");
List<MemberVO> list = memberList.getMemberList();
- 등록된 Session Bean의 JNDI 이름은 "Bean 클래스 명/Session Bean type"이 기본이다. Session Bean type은 remote, local 두가지를 가질수 잇다.
- JNDI명을 바꾸고 싶다면 MemberListBean.java 파일의 "@Stateless" Annotation에 "@Stateless(name="MemberService")"와 같이 설정해주면 되고 이럴 경우 JNDI 이름은 "MemberService/remote"로 변경된다.

참고 사항
Entity Bean은 Data의 영속성을 가지는 객체이고, VO는 클라이언트 뷰에 초점이 맞춰진 객체이다. EJB3을 설명하는 몇몇 문서에서는 클라이언트 뷰에 EntityBean을 마치 VO 처럼 전달하는 예제를 보여주고 있는데 이 두 객체는 명백히 그 사용성이 다르다. 본 예제에서는 Remote Session Bean -> Entity Bean 형태의 2단 구성을 보여주고 있지만 사실은 Remote SessionBean -> Local Session Bean -> Entity Bean의 3단 구성을 하는게 원칙이다. Entity Bean과 Value Object의 상호간의 변환은 Local Session Bean부분에서 처리되는게 바람직할 것이다.

댓글 없음:

댓글 쓰기

블록체인 개요 및 오픈소스 동향

블록체인(block chain) 블록체인은 공공 거래장부이며 가상 화폐로 거래할때 발생할때 발생할 수 있는 해킹을 막는 기술. 분산 데이터베이스의 한 형태로, 지속적으로 성장하는 데이터 기록 리스트로서 분산 노드의 운영자에 의한 임의 조작이 불가...