1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.ActiveRecord
.Framework
18 using System
.Collections
;
21 using NHibernate
.Type
;
24 /// Translates the <c>IInterceptor</c>
25 /// messages to instance possible hooks
27 public class HookDispatcher
: EmptyInterceptor
29 private static readonly HookDispatcher instance
= new HookDispatcher();
32 /// Initializes a new instance of the <see cref="HookDispatcher"/> class.
34 protected HookDispatcher()
39 /// Gets the sole instance.
41 /// <value>The instance.</value>
42 public static HookDispatcher Instance
44 get { return instance; }
48 /// Called just before an object is initialized
50 /// <param name="entity"></param>
51 /// <param name="id"></param>
52 /// <param name="propertyNames"></param>
53 /// <param name="state"></param>
54 /// <param name="types"></param>
56 /// The interceptor may change the <c>state</c>, which will be propagated to the persistent
57 /// object. Note that when this method is called, <c>entity</c> will be an empty
58 /// uninitialized instance of the class.</remarks>
59 /// <returns><c>true</c> if the user modified the <c>state</c> in any way</returns>
60 public override bool OnLoad(object entity
, object id
, object[] state
, string[] propertyNames
, IType
[] types
)
62 ActiveRecordHooksBase hookTarget
= entity
as ActiveRecordHooksBase
;
64 if (hookTarget
!= null)
66 return hookTarget
.BeforeLoad(id
, new DictionaryAdapter(propertyNames
, state
));
73 /// Called when an object is detected to be dirty, during a flush.
75 /// <param name="currentState"></param>
76 /// <param name="entity"></param>
77 /// <param name="id"></param>
78 /// <param name="previousState"></param>
79 /// <param name="propertyNames"></param>
80 /// <param name="types"></param>
82 /// The interceptor may modify the detected <c>currentState</c>, which will be propagated to
83 /// both the database and the persistent object. Note that all flushes end in an actual
84 /// synchronization with the database, in which as the new <c>currentState</c> will be propagated
85 /// to the object, but not necessarily (immediately) to the database. It is strongly recommended
86 /// that the interceptor <b>not</b> modify the <c>previousState</c>.
88 /// <returns><c>true</c> if the user modified the <c>currentState</c> in any way</returns>
89 public override bool OnFlushDirty(object entity
, object id
, object[] currentState
, object[] previousState
, string[] propertyNames
, IType
[] types
)
91 ActiveRecordHooksBase hookTarget
= entity
as ActiveRecordHooksBase
;
93 if (hookTarget
!= null)
95 return hookTarget
.OnFlushDirty(id
, new DictionaryAdapter(propertyNames
, previousState
), new DictionaryAdapter(propertyNames
, currentState
), types
);
103 /// Called before an object is saved
105 /// <param name="entity"></param>
106 /// <param name="id"></param>
107 /// <param name="propertyNames"></param>
108 /// <param name="state"></param>
109 /// <param name="types"></param>
111 /// The interceptor may modify the <c>state</c>, which will be used for the SQL <c>INSERT</c>
112 /// and propagated to the persistent object
114 /// <returns><c>true</c> if the user modified the <c>state</c> in any way</returns>
115 public override bool OnSave(object entity
, object id
, object[] state
, string[] propertyNames
, IType
[] types
)
117 ActiveRecordHooksBase hookTarget
= entity
as ActiveRecordHooksBase
;
119 if (hookTarget
!= null)
121 return hookTarget
.BeforeSave(new DictionaryAdapter(propertyNames
, state
));
128 /// Called before an object is deleted
130 /// <param name="entity"></param>
131 /// <param name="id"></param>
132 /// <param name="propertyNames"></param>
133 /// <param name="state"></param>
134 /// <param name="types"></param>
136 /// It is not recommended that the interceptor modify the <c>state</c>.
138 public override void OnDelete(object entity
, object id
, object[] state
, string[] propertyNames
, IType
[] types
)
140 ActiveRecordHooksBase hookTarget
= entity
as ActiveRecordHooksBase
;
142 if (hookTarget
!= null)
144 hookTarget
.BeforeDelete(new DictionaryAdapter(propertyNames
, state
));
149 /// Called before a flush
151 /// <param name="entities">The entities</param>
152 public override void PreFlush(ICollection entities
)
154 foreach(object entity
in entities
)
156 ActiveRecordHooksBase hookTarget
= entity
as ActiveRecordHooksBase
;
158 if (hookTarget
!= null)
160 hookTarget
.PreFlush();
166 /// Called after a flush that actually ends in execution of the SQL statements required to
167 /// synchronize in-memory state with the database.
169 /// <param name="entities">The entitites</param>
170 public override void PostFlush(ICollection entities
)
172 foreach(object entity
in entities
)
174 ActiveRecordHooksBase hookTarget
= entity
as ActiveRecordHooksBase
;
176 if (hookTarget
!= null)
178 hookTarget
.PostFlush();
184 /// Called when a transient entity is passed to <c>SaveOrUpdate</c>.
187 /// The return value determines if the object is saved
189 /// <item><c>true</c> - the entity is passed to <c>Save()</c>, resulting in an <c>INSERT</c></item>
190 /// <item><c>false</c> - the entity is passed to <c>Update()</c>, resulting in an <c>UPDATE</c></item>
191 /// <item><c>null</c> - Hibernate uses the <c>unsaved-value</c> mapping to determine if the object is unsaved</item>
194 /// <param name="entity">A transient entity</param>
195 /// <returns></returns>
196 public override object IsUnsaved(object entity
)
198 ActiveRecordHooksBase hookTarget
= entity
as ActiveRecordHooksBase
;
200 if (hookTarget
!= null)
202 return hookTarget
.IsUnsaved();
209 /// Called from <c>Flush()</c>. The return value determines whether the entity is updated
213 /// <item>an array of property indicies - the entity is dirty</item>
214 /// <item>an empty array - the entity is not dirty</item>
215 /// <item><c>null</c> - use Hibernate's default dirty-checking algorithm</item>
218 /// <param name="entity">A persistent entity</param>
219 /// <param name="currentState"></param>
220 /// <param name="id"></param>
221 /// <param name="previousState"></param>
222 /// <param name="propertyNames"></param>
223 /// <param name="types"></param>
224 /// <returns>An array of dirty property indicies or <c>null</c> to choose default behavior</returns>
225 public override int[] FindDirty(object entity
, object id
, object[] currentState
, object[] previousState
, string[] propertyNames
, IType
[] types
)
227 ActiveRecordHooksBase hookTarget
= entity
as ActiveRecordHooksBase
;
229 if (hookTarget
!= null)
231 return hookTarget
.FindDirty(id
, new DictionaryAdapter(propertyNames
, previousState
), new DictionaryAdapter(propertyNames
, currentState
), types
);
238 /// Instantiate the entity class. Return <c>null</c> to indicate that Hibernate should use the default
239 /// constructor of the class
241 /// <param name="type">A mapped type</param>
242 /// <param name="id">The identifier of the new instance</param>
243 /// <returns>An instance of the class, or <c>null</c> to choose default behaviour</returns>
244 public override object Instantiate(Type type
, object id
)