~raginggoblin/infolog/infolog

« back to all changes in this revision

Viewing changes to InfologServer/lib/hibernate-distribution-3.3.2.GA/project/documentation/manual/old/ko-KR/src/main/docbook/content/events.xml

  • Committer: Raging Goblin
  • Date: 2013-11-16 16:51:32 UTC
  • Revision ID: raging_goblin-20131116165132-weujnptzc88uy4ah
Mavenized the project, now using shared project InfologSync

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<?xml version='1.0' encoding="UTF-8"?>
2
 
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
3
 
 
4
 
<chapter id="events">
5
 
    <title>인터셉터들과 이벤트들</title>
6
 
 
7
 
    <para>
8
 
                어플리케이션이 Hibernate 내부에서 발생하는 어떤 이벤트들에 대해 반응하는 것에 흔히 유용하다. 이것은 어떤 종류의 일반적인 기능, 
9
 
                그리고 Hibernate의 확장 기능의 구현을 허용해준다.
10
 
    </para>
11
 
 
12
 
    <sect1 id="objectstate-interceptors" revision="3">
13
 
        <title>인터셉터들</title>
14
 
 
15
 
        <para>
16
 
            <literal>Interceptor</literal> 인터페이스는 영속 객체가 저장되고, 업데이트되고, 삭제되거나 로드되기 전에 영속 객체의 
17
 
                        프로퍼티들을 조사하고/하거나 처리하는 것을 어플리케이션에 허용해줌으로써 세션으로부터 어플리케이션으로의 콜백들을 제공한다. 
18
 
                        이것에 대한 한 가지 가능한 사용은 감사 정보를 추적하는 것이다. 예를 들어, 다음 <literal>Interceptor</literal>는 
19
 
            <literal>Auditable</literal>이 생성될 때 <literal>createTimestamp</literal>를 자동적으로 설정하고 
20
 
            <literal>Auditable</literal>이 업데이트될 때 <literal>lastUpdateTimestamp</literal> 프로퍼티를 업데이트 한다.
21
 
        </para>
22
 
        
23
 
        <para>
24
 
                        당신은 <literal>Interceptor</literal>를 직접 구현해야 하거나 (더 좋게는) 
25
 
            <literal>EmptyInterceptor</literal>를 확장(extend)해야 한다.
26
 
        </para>
27
 
 
28
 
        <programlisting><![CDATA[package org.hibernate.test;
29
 
 
30
 
import java.io.Serializable;
31
 
import java.util.Date;
32
 
import java.util.Iterator;
33
 
 
34
 
import org.hibernate.EmptyInterceptor;
35
 
import org.hibernate.Transaction;
36
 
import org.hibernate.type.Type;
37
 
 
38
 
public class AuditInterceptor extends EmptyInterceptor {
39
 
 
40
 
    private int updates;
41
 
    private int creates;
42
 
    private int loads;
43
 
 
44
 
    public void onDelete(Object entity,
45
 
                         Serializable id,
46
 
                         Object[] state,
47
 
                         String[] propertyNames,
48
 
                         Type[] types) {
49
 
        // do nothing
50
 
    }
51
 
 
52
 
    public boolean onFlushDirty(Object entity,
53
 
                                Serializable id,
54
 
                                Object[] currentState,
55
 
                                Object[] previousState,
56
 
                                String[] propertyNames,
57
 
                                Type[] types) {
58
 
 
59
 
        if ( entity instanceof Auditable ) {
60
 
            updates++;
61
 
            for ( int i=0; i < propertyNames.length; i++ ) {
62
 
                if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
63
 
                    currentState[i] = new Date();
64
 
                    return true;
65
 
                }
66
 
            }
67
 
        }
68
 
        return false;
69
 
    }
70
 
 
71
 
    public boolean onLoad(Object entity,
72
 
                          Serializable id,
73
 
                          Object[] state,
74
 
                          String[] propertyNames,
75
 
                          Type[] types) {
76
 
        if ( entity instanceof Auditable ) {
77
 
            loads++;
78
 
        }
79
 
        return false;
80
 
    }
81
 
 
82
 
    public boolean onSave(Object entity,
83
 
                          Serializable id,
84
 
                          Object[] state,
85
 
                          String[] propertyNames,
86
 
                          Type[] types) {
87
 
 
88
 
        if ( entity instanceof Auditable ) {
89
 
            creates++;
90
 
            for ( int i=0; i<propertyNames.length; i++ ) {
91
 
                if ( "createTimestamp".equals( propertyNames[i] ) ) {
92
 
                    state[i] = new Date();
93
 
                    return true;
94
 
                }
95
 
            }
96
 
        }
97
 
        return false;
98
 
    }
99
 
 
100
 
    public void afterTransactionCompletion(Transaction tx) {
101
 
        if ( tx.wasCommitted() ) {
102
 
            System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads);
103
 
        }
104
 
        updates=0;
105
 
        creates=0;
106
 
        loads=0;
107
 
    }
108
 
 
109
 
}]]></programlisting>
110
 
 
111
 
        <para>
112
 
                        인터셉터들은 다음 두 개의  특징들로 나타난다: <literal>Session</literal>-영역화 그리고 
113
 
            <literal>SessionFactory</literal>-영역화.
114
 
        </para>
115
 
 
116
 
        <para>
117
 
            <literal>Session</literal>-영역의 인터셉터는 세션이 하나의 <literal>Interceptor</literal>를 수용하는 
118
 
                        오버로드된  SessionFactory.openSession() 메소드들 중 하나를 사용하여 열릴 때 
119
 
                        지정된다.
120
 
        </para>
121
 
 
122
 
        <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
123
 
 
124
 
 
125
 
        
126
 
        <para>
127
 
            <literal>SessionFactory</literal>-영역의 인터셉터는 <literal>SessionFactory</literal>을 빌드하기에 앞서 
128
 
            <literal>Configuration</literal> 객체에 등록된다. 이 경우에, 공급되는 인터셉터는 그 <literal>SessionFactory</literal>로부터
129
 
                        열려진 모든 세션들에 적용될 것이다; 하나의 세션이 사용할 인터셉터를 명시적으로 지정하여 열리지 않는 한 이것은 참이다. 
130
 
            <literal>SessionFactory</literal>-영역의 인터셉터들은 세션-지정적인 상태를 저장하지 않도록 주의하여 쓰레드-안전해야 한다. 
131
 
                        왜냐하면 다중 세션들은 (잠정적으로) 이 인터셉터를 동시적으로 사용할 것이기 때문이다.
132
 
        </para>
133
 
    
134
 
        <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
135
 
 
136
 
    </sect1>
137
 
 
138
 
     <sect1 id="objectstate-events" revision="4">
139
 
        <title>이벤트 시스템</title>
140
 
 
141
 
        <para>
142
 
                        만일 당신이 당신의 영속 계층에서 특정 이벤트들에 대해 반응해야 한다면, 당신은 또한 Hibernate3 <emphasis>event</emphasis>
143
 
                        아키텍처를 사용할 수도 있다. 이벤트 시스템은 부가물로 사용될 수 있거나 인터셉터들에 대한 대체물로 사용될 수 있다.
144
 
        </para>
145
 
 
146
 
        <para>
147
 
                        본질적으로 <literal>Session</literal> 인터페이스의 모든 메소드들은 이벤트와 서로 관련되어 있다. 
148
 
                        당신은 <literal>LoadEvent</literal>, 
149
 
            <literal>FlushEvent</literal>, 등을 갖는다 (정의된 이벤트 타입들의 전체 리스트에 대해서는 XML 구성 파일 DTD 또는 
150
 
            <literal>org.hibernate.event</literal> 패키지를 참조하라). 하나의 요청이 이들 메소드들 중 하나에 의해 만들어질 때, 
151
 
            Hibernate <literal>Session</literal>은  적절한 이벤트를 생성시키고 그것을 그 타입의 구성된 이벤트 리스너에게 전달한다. 
152
 
                        박싱없이, 이들 리스너들은 그들 메소드들이 항상 귀결되었던 동일한 프로세싱을 구현한다. 하지만 당신이 리스너 인터페이스들 중 하나의 맞춤을 
153
 
                        구현하는 것이 자유롭고(예를 들어 <literal>LoadEvent</literal>는 <literal>LoadEventListener</literal> 인터페이스의 
154
 
                        등록된 구현에 의해 처리된다), 그 경우에 그들 구현은 <literal>Session</literal>에 대해 행해진 임의의 <literal>load()</literal> 
155
 
                        요청들을 처리할 책임이 있을 것이다.
156
 
        </para>
157
 
 
158
 
        <para>
159
 
                        리스너들은 효율적이게끔 싱글톤(singleton)들로 간주되어야 할 것이다; 이것은 그것들이 요청들 사이에서 공유되고, 따라서 임의의 상태를 
160
 
                        인스턴스 변수들로서 저장하지 말아야 함을 의미한다.
161
 
        </para>
162
 
 
163
 
        <para>
164
 
                        맞춤형 리스너는 그것이 편의적인 기저 클래스들(또는 리스너들이 이 용도로 final이 아닌 것으로 선언되므로 Hibernate 
165
 
            out-of-the-box에 의해 사용된 디폴트 이벤트 리스너들) 중 하나를 처리하고/하거나 확장하고자 원하는 이벤트들에 대해 
166
 
                        적절한 인터페이스를 구현해야 한다. 맞춤형 리스너들은 <literal>Configuration</literal> 객체를 통해 프로그램 상으로 
167
 
                        등록될 수 있거나, Hibernate 구성 XML 속에 지정될 수 있다 (properties 파일을 통한 선언적인 구성은 지원되지 않는다). 
168
 
                        다음은 맞춤형 load 이벤트 리스너에 대한 예제이다:
169
 
        </para>
170
 
 
171
 
        <programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
172
 
    // this is the single method defined by the LoadEventListener interface
173
 
    public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
174
 
            throws HibernateException {
175
 
        if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
176
 
            throw MySecurityException("Unauthorized access");
177
 
        }
178
 
    }
179
 
}]]></programlisting>
180
 
 
181
 
        <para>
182
 
                        당신은 또한 디폴트 리스너에 덧붙여 그 리스너를 사용하도록 Hibernate에게 알려주는 구성 엔트리를 필요로 한다:
183
 
        </para>
184
 
 
185
 
<programlisting><![CDATA[<hibernate-configuration>
186
 
    <session-factory>
187
 
        ...
188
 
        <event type="load">
189
 
            <listener class="com.eg.MyLoadListener"/>
190
 
            <listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
191
 
        </event>
192
 
    </session-factory>
193
 
</hibernate-configuration>]]></programlisting>
194
 
 
195
 
        <para>
196
 
                        대신에 당신은 그것을 프로그래밍 방식으로 등록할 수도 있다:
197
 
        </para>
198
 
 
199
 
        <programlisting><![CDATA[Configuration cfg = new Configuration();
200
 
LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
201
 
cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
202
 
 
203
 
        <para>
204
 
                        선언적으로 등록된 리스너들은 인스턴스들을 공유할 수 없다. 만일 동일한 클래스 이름이 여러 개의 <literal>&lt;listener/&gt;</literal> 
205
 
                        요소들에서 사용될 경우, 각각의 참조는 그 클래스에 대한 별도의 인스턴스로 귀결될 것이다. 만일 당신이 리스너 타입들 사이에서 리스너 인스턴스들을 
206
 
                        공유할 가용성을 필요로 할 경우 당신은 프로그래밍 방식의 등록 접근법을 사용해야 한다.
207
 
        </para>
208
 
 
209
 
        <para>
210
 
                        구성 동안에 왜 인터페이스를 구현하고 특정 타입을 지정하는가? 물론 리스너 구현은 여러 개의 이벤트 리스너 인터페이스들을 
211
 
                        구현할 수 있다. 등록 동안에 추가적으로 타입을 정의하는 것은 컨피그레이션 동안에 맞춤형 리스너들의 사용 여부를 전환시키는 것을 
212
 
                        더 쉽게 해준다.
213
 
        </para>
214
 
 
215
 
    </sect1>
216
 
    
217
 
    <sect1 id="objectstate-decl-security" revision="2">
218
 
        <title>Hibernate 선언적인 보안</title>
219
 
        <para>
220
 
                       대개 Hibernate 어플리케이션들에서 선언적인 보안은 session facade 계층 내에서 관리된다. 이제, Hibernate3는 어떤 액션들이 
221
 
           JACC를 통해 퍼미션을 주어지고, JAAS를 통해 인가되는 것을 허용해준다. 이것은 모든 아키텍처의 상단에 빌드된 옵션 기능이다.
222
 
        </para>
223
 
        
224
 
        <para>
225
 
                        먼저, 당신은 JAAS authorization 사용을 이용 가능하도록 하기 위해 적절한 이벤트 리스터들을 구성해야 한다.
226
 
        </para>
227
 
        
228
 
        <programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
229
 
<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
230
 
<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
231
 
<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
232
 
 
233
 
        <para>
234
 
            <literal>&lt;listener type="..." class="..."/&gt;</literal>는 특정 이벤트 타입에 대해 정확히 한 개의 
235
 
                        리스너가 존재할 때  단지 <literal>&lt;event type="..."&gt;&lt;listener class="..."/&gt;&lt;/event&gt;</literal>의 
236
 
                        단축형임을 노트하라.
237
 
        </para>
238
 
 
239
 
        <para>
240
 
                        다음으로, 여전히 <literal>hibernate.cfg.xml</literal> 내에서 퍼미션들을 role들에 바인드 시킨다 :
241
 
        </para>
242
 
        
243
 
        <programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
244
 
<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
245
 
        
246
 
        <para>
247
 
                        역할(role) 이름들은 당신의 JACC 프로바이더에 의해 인지된 역할(role)들이다.
248
 
        </para>
249
 
       
250
 
    </sect1>
251
 
 
252
 
</chapter>
253