2011년 5월 23일 월요일

The Service Locator Pattern

14. The Service Locator Pattern
J2EE 규약은 다른 리소스나 서비스들에 대한 접근을 JNDI에 위임한다. J2EE 호환 서버는 이런한 리소스나 서비스들을 JNDI 서버에 바인드함으로써 클라이언트가 네트워크의 어디에도 JNDI lookup 프로세스를 통해 리소스나 서비스들을 lookup 할수 있도록 한다. 이러한 리소스나 서비스의 종류는 EJBHome, DateSource, JMS ConnectionFactory, JMS Topic/Queue 등이 있다. 이러한 요소들의 객체는 JNDI API를 사용하여 얻어진다. JNDI 룩업을 수행하여 어떻게 벤더에서 다른 벤터로 변경하는 것이 가능할까? JNDI 룩업 수행의 반복은 시스템의 부하를 줄수 있다.
JNDI로부터 서비스를 호출해야 할 때 매번 사용자가 적절한 JNDI 서버에 연결하고, JNDI 환경 정보를 알아내어 서비스를 찾는다. 필요한 것은 JNDI로부터 다양한 서비스를 생성 하고 가져올수 있다는 단일점이다. 여기에서 Service Locator 패턴이 사용된다.
Service Locator 패턴은 단순하게 사용할 수 있는 인터페이스로 모든 JNDI 룩업방식을 추상화 한다. 사용자가 특정한 EJB나 JDBC등… 연결을 요청할 때 데이터 소스에 연결하려고 처음 생성했던 JDBC 커넥션 객체를 재사용하고, EJBHome 인터페이스를 케싱함으로써 JNDI 룩업의 호출 횟수를 최소화한다.

구조


의도
캐싱을 이용한 객체 재사용과 JNDI 룩업 프로세스을 줄여주고 퍼포먼스을 비약적으로 향상시킨다.

예제소스
package common;
import java.sql.*;
import javax.sql.DataSource;
import java.util.Hashtable;
import javax.naming.*;
import javax.ejb.*;
import javax.rmi.PortableRemoteObject;
import common.counter.CounterHome;
import entity.booking.BookingLocalHome;
import entity.city.CityLocalHome;
import entity.flight.FlightLocalHome;
import entity.customer.CustomerLocalHome;
import entity.hotel.HotelLocalHome;
import javax.jms.*;
import facade.customer.*;
import facade.citybreak.*;
import facade.bookingmsg.*;
public class ServiceLocator{
private static ServiceLocator serviceLocatorRef = null;
private static Hashtable ejbHomeCache = null;
private static Hashtable dataSourceCache = null;
private static Hashtable queueConnectionFactoryCache = null;
private static Hashtable queueCache = null;
private static Hashtable ejbLocalHomeCache = null;
public static final int COUNTER = 0;
public static final int BOOKING = 1;
public static final int FLIGHT = 3;
public static final int HOTEL = 5;
...
// 요청된 JNDI 이름
private static final String COUNTER_JNDINAME="ejb/Counter";
private static final String BOOKING_JNDINAME="java:comp/env/ejb/Booking";
private static final String FLIGHT_JNDINAME="java:comp/env/ejb/Flight";
private static final String HOTEL_JNDINAME="java:comp/env/ejb/Hotel";
...
// EJB Home 클래스들
private static final Class COUNTERCLASSREF = CounterHome.class;
private static final Class BOOKINGCLASSREF = BookingLocalHome.class;
private static final Class FLIGHTCLASSREF = FlightLocalHome.class;
private static final Class HOTELCLASSREF = HotelLocalHome.class;
...
// 싱글톤 생성자
static {
serviceLocatorRef = new ServiceLocator();
}
public ServiceLocator(){
ejbHomeCache = new Hashtable();
ejbLocalHomeCache = new Hashtable();
dataSourceCache = new Hashtable();
queueConnectionFactoryCache = new Hashtable();
queueCache = new Hashtable();
}
public static ServiceLocator getInstance(){
if (serviceLocatorRef == null) {
serviceLocatorRef = new ServiceLocator();
}
return serviceLocatorRef;
}
static private String getServiceName(int pServiceId)
throws ServiceLocatorException{
String serviceName = null;
switch (pServiceId){
case COUNTER:
serviceName = COUNTER_JNDINAME;
break;
case BOOKING:
serviceName = BOOKING_JNDINAME;
break;
case FLIGHT:
serviceName = FLIGHT_JNDINAME;
break;
case HOTEL:
serviceName = HOTEL_JNDINAME;
break;
default:
throw new ServiceLocatorException("Unable to locate the service requested in " +
"ServiceLocator.getServiceName() method. ");
}
return serviceName;
}
static private Class getEJBHomeRef(int pServiceId)
throws ServiceLocatorException{
Class homeRef = null;
switch (pServiceId){
case COUNTER:
homeRef = COUNTERCLASSREF;
break;
case BOOKING:
homeRef = BOOKINGCLASSREF;
break;
case FLIGHT:
homeRef = FLIGHTCLASSREF;
break;
case HOTEL:
homeRef = HOTELCLASSREF;
break;
default:
throw new ServiceLocatorException("Unable to locate the service requested in " +
"ServiceLocator.getEJBHomeRef() method. ");
}
return homeRef;
}
public EJBHome getEJBHome(int pServiceId)
throws ServiceLocatorException{
// 요청된 서비스에 eogks JNDI 이름을 찾으려 시도한다.
String serviceName = getServiceName(pServiceId);
EJBHome ejbHome = null;
try{
// EJBLocal Home 인터페이스를 캐시에서 찾을수 있는지 체크한다.
if (ejbHomeCache.containsKey(serviceName)){
ejbHome = (EJBHome) ejbHomeCache.get(serviceName);
return ejbHome;
}
else{
// 캐시에서 찾을수 없다면 JNDI에서 룩업하고 캐시에 저장한다.
Context ctx = new InitialContext();
Object jndiRef = ctx.lookup(serviceName);
Object portableObj =
PortableRemoteObject.narrow(jndiRef, getEJBHomeRef(pServiceId));
ejbHome = (EJBHome) portableObj;
ejbHomeCache.put(serviceName, ejbHome);
return ejbHome;
}
}
catch(NamingException e){
throw new ServiceLocatorException("Naming exception error in ServiceLocator.getEJBHome()" + e);
}
catch(Exception e){
throw new ServiceLocatorException("General exception in ServiceLocator.getEJBHome" + e);
}
}
public EJBLocalHome getEJBLocalHome(int pServiceId)
throws ServiceLocatorException{
String serviceName = getServiceName(pServiceId);
EJBLocalHome ejbLocalHome = null;
try{
if (ejbLocalHomeCache.containsKey(serviceName)){
ejbLocalHome = (EJBLocalHome) ejbLocalHomeCache.get(serviceName);
return ejbLocalHome;
}
else{
Context ctx = new InitialContext();
Object jndiRef = ctx.lookup(serviceName);
ejbLocalHome = (EJBLocalHome) jndiRef;
ejbLocalHomeCache.put(serviceName, ejbLocalHome);
return ejbLocalHome;
}
}
catch(NamingException e){
throw new ServiceLocatorException("Naming exception error in ServiceLocator.getEJBLocalHome()" + e);
}
catch(Exception e){
throw new ServiceLocatorException("General exception in ServiceLocator.getEJBLocalHome" + e);
}
}
public java.sql.Connection getDBConn(int pServiceId)
throws ServiceLocatorException{
String serviceName = getServiceName(pServiceId);
java.sql.Connection conn = null;
try{
if (dataSourceCache.containsKey(serviceName)){
DataSource ds = (DataSource) dataSourceCache.get(serviceName);
conn = ((DataSource)ds).getConnection();
return conn;
}
else{
Context ctx = new InitialContext();
DataSource newDataSource = (DataSource) ctx.lookup(serviceName);
dataSourceCache.put(serviceName, newDataSource);
conn = newDataSource.getConnection();
return conn;
}
}
catch(SQLException e){
throw new ServiceLocatorException("A SQL error has occurred in ServiceLocator.getDBConn()" + e);
}
catch(NamingException e){
throw new ServiceLocatorException("A JNDI Naming exception has occurred in ServiceLocator.getDBConn()" + e);
}
catch(Exception e){
throw new ServiceLocatorException("An exception has occurred in ServiceLocator.getDBConn()" + e);
}
}
public QueueConnection getJMSQueueConn(int pServiceId) throws ServiceLocatorException {
...
}
public Queue getJMSQueue(int pServiceId) throws ServiceLocatorException {
...
}
}

댓글 없음:

댓글 쓰기

ETL 솔루션 환경

ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...