mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-03-03 16:29:13 +00:00
git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@7183 1b8cb986-b30d-0410-93ca-fae66ebed9b2
220 lines
11 KiB
XML
220 lines
11 KiB
XML
<chapter id="events">
|
|
<title>인터셉터들과 이벤트들</title>
|
|
|
|
<para>
|
|
어플리케이션이 Hibernate 내부에서 발생하는 어떤 이벤트들에 대해 반응하는 것에 흔히 유용하다. 이것은 어떤 종류의 일반적인 기능,
|
|
그리고 Hibernate의 확장 기능의 구현을 허용해준다.
|
|
</para>
|
|
|
|
<sect1 id="objectstate-interceptors" revision="1">
|
|
<title>인터셉터들</title>
|
|
|
|
<para>
|
|
<literal>Interceptor</literal> 인터페이스는 영속 객체가 저장되고, 업데이트되고, 삭제되거나 로드되기 전에 영속 객체의
|
|
프로퍼티들을 조사하고/하거나 처리하는 것을 어플리케이션에 허용해줌으로써 세션으로부터 어플리케이션으로의 콜백들을 제공한다.
|
|
이것에 대한 한 가지 가능한 사용은 감사 정보를 추적하는 것이다. 예를 들어, 다음 <literal>Interceptor</literal>는
|
|
<literal>Auditable</literal>이 생성될 때 <literal>createTimestamp</literal>를 자동적으로 설정하고
|
|
<literal>Auditable</literal>이 업데이트될 때 <literal>lastUpdateTimestamp</literal> 프로퍼티를 업데이트 한다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[package org.hibernate.test;
|
|
|
|
import java.io.Serializable;
|
|
import java.util.Date;
|
|
import java.util.Iterator;
|
|
|
|
import org.hibernate.Interceptor;
|
|
import org.hibernate.type.Type;
|
|
|
|
public class AuditInterceptor implements Interceptor, Serializable {
|
|
|
|
private int updates;
|
|
private int creates;
|
|
|
|
public void onDelete(Object entity,
|
|
Serializable id,
|
|
Object[] state,
|
|
String[] propertyNames,
|
|
Type[] types) {
|
|
// do nothing
|
|
}
|
|
|
|
public boolean onFlushDirty(Object entity,
|
|
Serializable id,
|
|
Object[] currentState,
|
|
Object[] previousState,
|
|
String[] propertyNames,
|
|
Type[] types) {
|
|
|
|
if ( entity instanceof Auditable ) {
|
|
updates++;
|
|
for ( int i=0; i < propertyNames.length; i++ ) {
|
|
if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
|
|
currentState[i] = new Date();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public boolean onLoad(Object entity,
|
|
Serializable id,
|
|
Object[] state,
|
|
String[] propertyNames,
|
|
Type[] types) {
|
|
return false;
|
|
}
|
|
|
|
public boolean onSave(Object entity,
|
|
Serializable id,
|
|
Object[] state,
|
|
String[] propertyNames,
|
|
Type[] types) {
|
|
|
|
if ( entity instanceof Auditable ) {
|
|
creates++;
|
|
for ( int i=0; i<propertyNames.length; i++ ) {
|
|
if ( "createTimestamp".equals( propertyNames[i] ) ) {
|
|
state[i] = new Date();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void postFlush(Iterator entities) {
|
|
System.out.println("Creations: " + creates + ", Updates: " + updates);
|
|
}
|
|
|
|
public void preFlush(Iterator entities) {
|
|
updates=0;
|
|
creates=0;
|
|
}
|
|
|
|
...
|
|
|
|
}]]></programlisting>
|
|
|
|
<para>
|
|
세션이 생성될 때 인터셉터가 지정될 것이다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
|
|
|
|
<para>
|
|
당신은 또한 <literal>Configuration</literal>을 사용하여 인터셉터를 전역 레벨 상에 설정할 수도 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="objectstate-events" revision="2">
|
|
<title>이벤트 시스템</title>
|
|
|
|
<para>
|
|
만일 당신이 당신의 영속 계층에서 특별한 이벤트들에 대해 반응해야 한다면, 당신은 또한 Hibernate3 <emphasis>이벤트</emphasis>
|
|
아키텍처를 사용할 수도 있다. 이벤트 시스템은 부가물로 사용될 수 있거나 인터셉터들에 대한 대체물로 사용될 수 있다.
|
|
</para>
|
|
|
|
<para>
|
|
본질적으로 <literal>Session</literal> 인터페이스의 모든 메소드들은 이벤트와 서로 관련되어 있다. 당신은 <literal>LoadEvent</literal>,
|
|
<literal>FlushEvent</literal>, 등을 갖는다 (정의된 이벤트 타입들의 전체 리스트에 대해서는 XML 구성 파일 DTD 또는
|
|
<literal>org.hibernate.event</literal> 패키지를 참조하라). 하나의 요청이 이들 메소드들 중 하나에 의해 만들어질 때,
|
|
Hibernate <literal>Session</literal>은 적절한 이벤트를 생성시키고 그것을 그 타입에 대한 구성된 이벤트 리스너에게 전달한다.
|
|
박싱없이, 이들 리스너들은 그들 메소드들이 항상 귀결되었던 동일한 프로세싱을 구현한다. 하지만 당신이 리스너 인터페이스들 중 하나의 맞춤을
|
|
구현하는 것이 자유롭고(예를 들어 <literal>LoadEvent</literal>는 <literal>LoadEventListener</literal> 인터페이스의
|
|
등록된 구현에 의해 처리된다), 그 경우에 그들 구현은 <literal>Session</literal>에 대해 행해진 임의의 <literal>load()</literal>
|
|
요청들을 처리할 책임이 있을 것이다.
|
|
</para>
|
|
|
|
<para>
|
|
리스너들은 효율적이게끔 싱글톤(singleton)들로 간주되어야 할 것이다; 이것은 그것들이 요청들 사이에서 공유되고, 따라서 임의의 상태를
|
|
인스턴스 변수들로서 저장하지 말아야 함을 의미한다.
|
|
</para>
|
|
|
|
<para>
|
|
맞춤형 리스너는 그것이 편의적인 기저 클래스들(또는 리스너들이 이 용도로 final이 아닌 것으로 선언되므로 Hibernate
|
|
out-of-the-box에 의해 사용된 디폴트 이벤트 리스너들) 중 하나를 처리하고자 그리고/또는 확장하고자 원하는 이벤트들에 대해
|
|
적절한 인터페이스를 구현해야 한다. 맞춤형 리스너들은 <literal>Configuration</literal> 객체를 통해 프로그램 상으로
|
|
등록될 수 있거나, Hibernate 구성 XML 속에 지정될 수 있다 (properties 파일을 통한 선언적인 구성은 지원되지 않는다).
|
|
다음은 맞춤형 load 이벤트 리스너에 대한 예제이다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[public class MyLoadListener extends DefaultLoadEventListener {
|
|
// this is the single method defined by the LoadEventListener interface
|
|
public Object onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
|
|
throws HibernateException {
|
|
if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
|
|
throw MySecurityException("Unauthorized access");
|
|
}
|
|
return super.onLoad(event, loadType);
|
|
}
|
|
}]]></programlisting>
|
|
|
|
<para>
|
|
당신은 또한 디폴트 리스너 대신에 해당 리스너를 사용하도록 Hibernate에게 알려주는 구성 엔트리를 필요로 한다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<hibernate-configuration>
|
|
<session-factory>
|
|
...
|
|
<listener type="load" class="MyLoadListener"/>
|
|
</session-factory>
|
|
</hibernate-configuration>]]></programlisting>
|
|
|
|
<para>
|
|
대신에 당신은 그것을 프로그래밍 방식으로 등록할 수도 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[Configuration cfg = new Configuration();
|
|
cfg.getSessionEventListenerConfig().setLoadEventListener( new MyLoadListener() );]]></programlisting>
|
|
|
|
<para>
|
|
선언적으로 등록된 리스너들은 인스턴스들을 공유할 수 없다. 만일 동일한 클래스 이름이 여러 <literal><listener/></literal>
|
|
요소들에서 사용될 경우, 각각의 참조는 그 클래스에 대한 별도의 인스턴스로 귀결될 것이다. 만일 당신이 리스너 타입들 사이에서 리스너 인스턴스들을
|
|
공유할 가용성을 필요로 할 경우 당신은 프로그래밍 방식의 등록 접근법을 사용해야 한다.
|
|
</para>
|
|
|
|
<para>
|
|
컨피그레이션 동안에 왜 인터페이스를 구현하고 특정 타입을 지정하는가? 물론 리스너 구현은 여러 개의 이벤트 리스너 인터페이스들을
|
|
구현할 수 있다. 등록 동안에 추가적으로 타입을 정의하는 것은 컨피그레이션 동안에 맞춤형 리스너들의 사용 여부를 전환시키는 것을
|
|
더 쉽게 해준다.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="objectstate-decl-security">
|
|
<title>Hibernate 선언적인 보안</title>
|
|
<para>
|
|
대개 Hibernate 어플리케이션들에서 선언적인 보안은 session facade 계층 내에서 관리된다. 이제, Hibernate3는 어떤 액션들이
|
|
JACC를 통해 퍼미션을 주어지고, JAAS를 통해 인가되는 것을 허용해준다. 이것은 모든 아키텍처의 상단에 빌드된 옵션 기능이다.
|
|
</para>
|
|
|
|
<para>
|
|
먼저, 당신은 JAAS authorization 사용을 이용 가능하도록 하기 위해 적절한 이벤트 리스터들을 구성해야 한다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
|
|
<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
|
|
<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
|
|
<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
|
|
|
|
<para>
|
|
다음으로, 여전히 <literal>hibernate.cfg.xml</literal> 내에서 퍼미션들을 role들에 바인드 시킨다 :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
|
|
<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
|
|
|
|
<para>
|
|
역할(role) 이름들은 당신의 JACC 프로바이더에 의해 인지된 역할(role)들이다.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|
|
|