목차 >> Data Access Object(DAO) +- GlueGenericDao +- GlueJdbcDao ----+- Glue Query File(SQL) ----+- Query Manager ----+- Activity에서의 dao 사용 ----+- GlueColumnManager ----+- Audit Data 처리 ----+- Reuse Activity |
GlueJdbcDao는 SpringJDBC를 이용해서 추상화된 CRUD 오퍼레이션을 제공하는 구현체입니다.
GlueJdbcDao의 상속관계 및 메소드는 Java Doc을 참고합니다 (GlueAPI).
GlueJdbcDao의 필수 속성(property)는 다음과 같습니다.
<bean id="biz-dao" class="com.poscoict.glueframework.dao.jdbc.GlueJdbcDao"> <property name="dataSource" ref="dataSource"/> <property name="queryManager" ref="queryManager"/> </bean>
다음은 추가 속성(property)입니다.
GlueJdbcDao의 속성에 나와 있듯이 GlueJdbcDao를 사용하기 위해서는 관련 빈이 필요합니다.
GlueJdbcDao의 관련 bean은 그림과 같고, applicationContext.xml은 다음과 같습니다.
그림 : GlueJdbcDao의 bean들과의 관계 |
<bean id="dao-1" class="com.poscoict.glueframework.dao.jdbc.GlueJdbcDao"> <property name="dataSource" ref="dataSource-1"/> <property name="queryManager" ref="queryManager"/> </bean> <bean id="dataSource-1" class= . . . /> <bean id="transactionManager-1" class= . . . /> <bean id="dao-2" class="com.poscoict.glueframework.dao.jdbc.GlueJdbcDao"> <property name="dataSource" ref="dataSource-2"/> <property name="queryManager" ref="queryManager"/> </bean> <bean id="transactionManager-2" class= . . . /> <bean id="queryManager" class= . . . /> <bean id="cacheManager" class= . . . /> <bean id="queryLoader" class= . . . />
빈(bean)들간의 관계성은 모두 자바 인터페이스를 기반으로 레퍼린싱 되고 있습니다. 그러므로, 실제 구현 된 소스 코드를 변경하지 않고도 빈 설정 파일만 수정 해주면 변경된 로직으로 작동하는 새로운 오브젝트를 각 빈들과 연관을 지을 수 있습니다.
다시 말해서 설정파일(applicationContext.xml) 재정의만을 통해서 새로 제작된 DAO, QueryManager 등을 손쉽게 교체할 수 있다는 것을 의미합니다. 결론적으로 유지보수성 및 확장성이 아주 뛰어납니다.
GlueJdbcDao 에서는 2가지 유형의 SQL을 사용할 수 있습니다.
SELECT * FROM EMP WHERE DEPTNO=? AND SAL>?
SELECT * FROM EMP WHERE DEPTNO=:deptno AND SAL>:sal
2가지 유형의 SQL은 Glue Query File에서 isNamed 속성을 통해 구분됩니다.
<?xml version="1.0" encoding="UTF-8"?> <queryMap desc="sql" xmlns="http://www.poscoict.com/glueframework/query"> <query id="sql.type.1" desc="기본SQL" isNamed="false"> <![CDATA[ SELECT * FROM EMP WHERE DEPTNO=? AND SAL>? ]]> </query> <query id="sql.type.2" desc="NamedSQL" isNamed="true"> <![CDATA[ SELECT * FROM EMP WHERE DEPTNO=:deptno AND SAL>:sal ]]> </query> </queryMap>
QueryManager의 구현체인 GlueQueryManagerImpl은 다음과 같은 속성을 갖습니다 (GlueAPI).
다음은 applicationContext.xml 예제입니다.
QueryManager를 사용하기 위해서는 관련 빈(bean)을 다음과 같이 추가할 수 있습니다.
<bean id="queryManager" class="com.poscoict.glueframework.dao.manager.GlueQueryManagerImpl"> <property name="cacheManager" ref="cacheManager"/> <property name="queryLoader" ref="queryLoader"/> </bean> <bean id="queryLoader" class="com.poscoict.glueframework.dao.manager.GlueQueryLoader"/> <bean id="cacheManager" class= . . . />
GlueQueryManagerImpl 이 참조하는 QueryLoader는 다음과 같은 속성을 갖을 수 있습니다 (GlueAPI).
<bean id="queryLoader" class="com.poscoict.glueframework.dao.manager.GlueQueryLoader"/>
<bean id="queryLoader" class="com.poscoict.glueframework.dao.manager.GlueQueryLoader"> <property name="rootPath" ref="path/biz"/> </bean>
<bean id="queryLoader" class="com.poscoict.glueframework.dao.manager.GlueQueryLoader"> <property name="extraQueryFiles"> <list> <value>path/biz1-query.glue_sql</value> <value>path/biz2-query.glue_sql</value> </list> </property> </bean>
GlueJdbcDao는 2종류의 Query를 사용할 수 있습니다.
SELECT * FROM EMP WHERE DEPTNO=? AND SAL>?
public class BizActivity extends GlueActivity<GlueContext> { public String runActivity( GlueContext ctx ) { Object deptno = . . .; Object sal = . . .; String queryId = . . .; List paramList = new ArrayList(); paramList.add( deptno ); paramList.add( sal ); GlueParameter<List> param = new GlueParameter<List>(); param.setParameter( paramList ); // GlueParameter<List> param = new GlueParameter<List>( paramList ); GlueGenericDao dao = this.getDao( "biz-dao" ); // this.getDao( this.getProperty( "dao" ) ) List<Map> result = dao.find( queryId, param ); . . .
Query File을 사용하지 않은 경우는, 즉 Java Code에 다음과 같이 SQL을 포함할 수 있습니다.
List<Map> result = dao.findByQueryStatement("SELECT * FROM EMP WHERE DEPTNO=? AND SAL>?", param)
SELECT * FROM EMP WHERE DEPTNO=:deptno AND SAL>:sal
public class BizActivity extends GlueActivity<GlueContext> { public String runActivity( GlueContext ctx ) { Object deptno = . . .; Object sal = . . .; String queryId = . . .; Map paramMap = new HashMap(); paramMap.put( "deptno", deptno ); paramMap.put( "sal", sal ); GlueParameter<Map> param = new GlueParameter<Map>(); param.setParameter( paramMap ); // GlueParameter<Map> param = new GlueParameter<Map>( paramMap ); GlueGenericDao dao = this.getDao( "biz-dao" ); // this.getDao( this.getProperty( "dao" ) ) List<Map> result = dao.find( queryId, param ); . . .
Query File을 사용하지 않은 경우는, 즉 Java Code에 다음과 같이 SQL을 포함할 수 있습니다.
result = dao.findByQueryStatement("SELECT * FROM EMP WHERE DEPTNO=:deptno AND SAL>:sal", param)
ColumnManager는 dao의 find() 실행결과를 List<Map> 구조에서 GlueRowSet<GlueRow>의 구조로 변환하는 기능을 갖습니다. 이러한 변환과정을 통해 GlueRowSet은 GlueColumnDef 정보를 포함하게 됩니다.
이러한 기능은 기본SQL(? 사용)일 경우 지원됩니다.
GlueColumnManager는 다음과 같은 속성을 갖습니다 (GlueAPI).
<bean id="dao" class="com.poscoict.glueframework.dao.jdbc.GlueJdbcDao"> . . . <property name="columnManager" ref="columnManager"/> </bean> <bean id="columnManager" class="com.poscoict.glueframework.dao.manager.GlueColumnManager"> <property name="cacheManager" ref="cacheManager"/> </bean> <bean id="cacheManager" class= . . . />
다음은 GlueColumnManager 사용과 관련된 Class입니다.
<bean id="biz-dao" class="com.poscoict.glueframework.dao.jdbc.GlueJdbcDao"> <property name="dataSource" ref="dataSource"/> <property name="queryManager" ref="queryManager"/> <property name="columnManager" ref="columnManager"/> </bean> <bean id="columnManager" class="com.poscoict.glueframework.dao.manager.GlueColumnManager"> <property name="cacheManager" ref="cacheManager"/> </bean>
public class SampleActivity extends GlueActivity<GlueContext> { @Override public String runActivity( GlueContext ctx ) { GlueGenericJdbcDao dao = (GlueGenericJdbcDao)this.getDao("biz-dao"); List paramList = . . . GlueRowSet rowSet = dao.findByQueryStatement("select * from EMP where deptno=?", new GlueParameter<List>(paramList); ); GlueColumnDef[] def = rowSet.getColumnDefs(); while(rowSet.hasNext()) { GlueRow row = rowSet.next(); for(int i=0, iz=def.length; i < iz; i++) { System.out.println("ColumnDef - Name : "+def[i].getName()); System.out.println("ColumnDef - Type : "+def[i].getType()); System.out.println("ColumnDef - Length : "+def[i].getLength()); System.out.println("ColumnDef - Precision : "+def[i].getPrecision()); System.out.println("ColumnDef - Scale : "+def[i].getScale()); System.out.println("Data : "+row.getAttribute(def[i].getName())); } } return GlueBizControlConstants.SUCCESS; } }
관계형 데이타베이스에서 모든 테이블이 not null 제약조건의 audit 컬럼들을 동일하게 포함할 때, insert/update 수행시 해당 컬럼값을 자동으로 binding 해 줄 수 있습니다.
이를 위해 glue.property에 다음 property가 포함되어 있어야 합니다.
여러 개의 Audit항목이 존재 할 경우 컴마(,)를 구분자로 사용합니다. Audit 항목이 시간정보일 경우 timestamp 유형은 #current_timestamp# 를 붙여주고, Date 유형은#current_date# 를 붙여줍니다.
glue.properties 가 다음과 같을 경우 SQL 유형별 예제입니다.
audit.insert.key=cid,cip,cdt#current_timestamp#,uid,uip,udt#current_timestamp# audit.update.key=uid,uip,udt#current_timestamp#
insert into EMP_AUDIT( CREATE_ID, CREATE_IP, CREATE_DT, UPDATE_ID, UPDATE_IP, UPDATE_DT, EMPNO, ENAME, SAL, DEPTNO ) values(?,?,?,?,?,?,?,?,?,?)
기본 SQL이 위와 같을 때 GlueParameter의 setAuditAttributes() 를 사용한 Java Code 예제입니다.
List<Object> paramList = new ArrayList<Object>(); paramList.put( 1118 ); //EMPNO paramList.put( "USER8" ); //ENAME paramList.add( 7000 ); //SAL paramList.put( 10 ); //DEPTNO param = new GlueParameter<ArrayList<Object>>( paramList ); param.setAuditAttributes( ctx.getAuditAttributes(); ); dao.insert( queryid, param );
기본 SQL이 위와 같을 때 reuse activity의 is-audit property를 사용한 예제입니다.
<activity name="Insert" class="com.poscoict.glueframework.biz.activity.GlueJdbcInsert"> <property name="dao" value=". . ." /> <property name="sql-key" value=". . ." /> <property name="param-count" value="4" /> <property name="param0" value="EMPNO" /> <property name="param1" value="ENAME" /> <property name="param2" value="SAL" /> <property name="param3" value="DEPTNO" /> <property name="is-audit" value="true" /> <transition name="success" value=". . ." /> </activity>
insert into EMP_AUDIT (EMPNO, ENAME, SAL, DEPTNO, CREATE_ID, CREATE_IP, CREATE_DT, UPDATE_ID, UPDATE_IP, UPDATE_DT )values(:empno, :ename, :sal, :deptno, :cid, :cip, :cdt, :uid, :uip, :udt )
Named SQL이 위와 같을 때 GlueParameter의 setAuditAttributes() 를 사용한 Java Code 예제입니다.
Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put( "sal", 7000 ); paramMap.put( "ename", "USER8" ); paramMap.put( "empno", 1118 ); paramMap.put( "deptno", 10 ); param = new GlueParameter<HashMap<String, Object>>( paramMap ); param.setAuditAttributes( ctx.getAuditAttributes(); ); dao.insert( queryid, param );
기본 SQL이 위와 같을 때 reuse activity의 is-audit property를 사용한 예제입니다.
<activity name="Insert" class="com.poscoict.glueframework.biz.activity.GlueJdbcInsert"> <property name="dao" value=". . ." /> <property name="sql-key" value=". . ." /> <property name="param-bindings" value="empno=EMPNO|ename=ENAME|sal=SAL|deptno=DEPTNO" /> <property name="is-audit" value="true" /> <transition name="success" value=". . ." /> </activity>
다음은 Core >> Glue Service 부분에서 'Glue Service 실행 Layer' 부분에 나타나는 Control Layer에 해당하는 Class입니다. 아래 Class 에서는 Glue Service 실행 전에 glue.properties에 Audit 항목을 위한 property가 있는지 확인합니다. 있다면 GlueAuditAttributes를 생성하여 GlueContext에 설정하는 로직이 수행됩니다.
다음 코드를 참고해서 필요시 GlueAuditAttributes 를 생성할 수 있습니다. 즉, Control Layer에 해당하는 Class를 만들거나, Audit Data를 변경하고자 하는 경우 입니다.
if ( GlueStaticContext.isAudit() ) { ctx.setAuditAttributes( new GlueAuditAttributes( ctx ) ); }
if ( GlueStaticContext.isAudit() ) { Map map = new HashMap() map.put( "cid", id ); map.put( "cip", ip ); map.put( "uid", id ); map.put( "uip", ip ); ctx.setAuditAttributes( new GlueAuditAttributes( map ) ); }
GlueJdbcDao를 사용한 reuse Activity는 다음과 같은 것이 제공되고 있습니다.