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
17 using System
.Collections
.Generic
;
20 using NHibernate
.Type
;
21 using Castle
.ActiveRecord
.Framework
.Internal
;
22 using Castle
.Components
.Validator
;
25 /// This class processes the events generated by NHibernate and validates objects
26 /// where the object is not derived from ActiveRecordBase. If you want to use it
27 /// you could create a facility that replaces the default HookDispatcher along
28 /// the lines of the following:
30 /// public class ValidateFacility : IFacility
32 /// public void Init(IKernel kernel, Castle.Core.Configuration.IConfiguration facilityConfig)
34 /// InterceptorFactory.Create = new InterceptorFactory.CreateInterceptor(CreateValidationInterceptor);
37 /// private IInterceptor CreateValidationInterceptor()
39 /// return ValidationHookDispatcher.Instance;
44 public class ValidationHookDispatcher
: EmptyInterceptor
46 private static readonly ValidationHookDispatcher instance
= new ValidationHookDispatcher();
49 /// Initializes a new instance of the ValidationHookDispatcher class.
51 protected ValidationHookDispatcher()
56 /// Gets the sole instance.
58 /// <value>The instance.</value>
59 public static ValidationHookDispatcher Instance
61 get { return instance; }
65 /// Called when an object is detected to be dirty, during a flush.
67 /// <param name="currentState"></param>
68 /// <param name="entity"></param>
69 /// <param name="id"></param>
70 /// <param name="previousState"></param>
71 /// <param name="propertyNames"></param>
72 /// <param name="types"></param>
74 /// The interceptor may modify the detected <c>currentState</c>, which will be propagated to
75 /// both the database and the persistent object. Note that all flushes end in an actual
76 /// synchronization with the database, in which as the new <c>currentState</c> will be propagated
77 /// to the object, but not necessarily (immediately) to the database. It is strongly recommended
78 /// that the interceptor <b>not</b> modify the <c>previousState</c>.
80 /// <returns><c>true</c> if the user modified the <c>currentState</c> in any way</returns>
81 public override bool OnFlushDirty(object entity
, object id
, object[] currentState
, object[] previousState
, string[] propertyNames
, IType
[] types
)
83 IsValid(entity
, RunWhen
.Update
);
89 /// Called before an object is saved
91 /// <param name="entity"></param>
92 /// <param name="id"></param>
93 /// <param name="propertyNames"></param>
94 /// <param name="state"></param>
95 /// <param name="types"></param>
97 /// The interceptor may modify the <c>state</c>, which will be used for the SQL <c>INSERT</c>
98 /// and propagated to the persistent object
100 /// <returns><c>true</c> if the user modified the <c>state</c> in any way</returns>
101 public override bool OnSave(object entity
, object id
, object[] state
, string[] propertyNames
, IType
[] types
)
103 IsValid(entity
, RunWhen
.Insert
);
108 private void IsValid(object entity
)
110 IsValid(entity
, RunWhen
.Everytime
);
113 private void IsValid(object entity
, RunWhen runWhen
)
115 ValidatorRunner runner
= new ValidatorRunner(ActiveRecordModelBuilder
.ValidatorRegistry
);
117 if (!runner
.IsValid(entity
, runWhen
))
119 List
<string> errorList
= new List
<string>();
121 ErrorSummary summary
= runner
.GetErrorSummary(entity
);
123 foreach (string invalidProperty
in summary
.InvalidProperties
)
125 foreach (string errorMessage
in summary
.GetErrorsForProperty(invalidProperty
))
127 errorList
.Add(string.Format("{0} - {1}", invalidProperty
, errorMessage
));
131 string[] errorMessages
= errorList
.ToArray();
132 throw new ValidationException("Can't save or update as there is one (or more) field that has not passed the validation test", errorMessages
);