65a9025900758416ebca9e97a187314c72a6dab0
[mono.git] / mcs / class / referencesource / System.Workflow.Activities / Common / ValidationHelpers.cs
1 // Copyright (c) Microsoft Corporation. All rights reserved. 
2 //  
3 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
4 // WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
5 // WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 
6 // THE ENTIRE RISK OF USE OR RESULTS IN CONNECTION WITH THE USE OF THIS CODE 
7 // AND INFORMATION REMAINS WITH THE USER. 
8 //  
9
10 /*********************************************************************
11  * NOTE: A copy of this file exists at: WF\Common\Shared
12  * The two files must be kept in sync.  Any change made here must also
13  * be made to WF\Common\Shared\ValidationHelpers.cs
14 *********************************************************************/
15 namespace System.Workflow.Activities.Common
16 {
17     #region Imports
18
19     using System;
20     using System.Diagnostics;
21     using System.Collections;
22     using System.Collections.Generic;
23     using System.Reflection;
24     using System.CodeDom.Compiler;
25     using System.Workflow.ComponentModel.Design;
26     using System.Workflow.ComponentModel.Compiler;
27     using System.Collections.Specialized;
28     using System.ComponentModel.Design.Serialization;
29     using System.Workflow.ComponentModel;
30     #endregion
31
32     internal static class ValidationHelpers
33     {
34         #region Validation & helpers for ID and Type
35
36         internal static void ValidateIdentifier(IServiceProvider serviceProvider, string identifier)
37         {
38             if (serviceProvider == null)
39                 throw new ArgumentNullException("serviceProvider");
40
41             SupportedLanguages language = CompilerHelpers.GetSupportedLanguage(serviceProvider);
42             CodeDomProvider provider = CompilerHelpers.GetCodeDomProvider(language);
43             if (language == SupportedLanguages.CSharp && identifier.StartsWith("@", StringComparison.Ordinal) ||
44                 language == SupportedLanguages.VB && identifier.StartsWith("[", StringComparison.Ordinal) && identifier.EndsWith("]", StringComparison.Ordinal) ||
45                 !provider.IsValidIdentifier(identifier))
46             {
47                 throw new Exception(SR.GetString(SR.Error_InvalidLanguageIdentifier, identifier));
48             }
49         }
50
51         internal static ValidationError ValidateIdentifier(string propName, IServiceProvider context, string identifier)
52         {
53             if (context == null)
54                 throw new ArgumentNullException("context");
55
56             ValidationError error = null;
57             if (identifier == null || identifier.Length == 0)
58                 error = new ValidationError(SR.GetString(SR.Error_PropertyNotSet, propName), ErrorNumbers.Error_PropertyNotSet);
59             else
60             {
61                 try
62                 {
63                     ValidationHelpers.ValidateIdentifier(context, identifier);
64                 }
65                 catch (Exception e)
66                 {
67                     error = new ValidationError(SR.GetString(SR.Error_InvalidIdentifier, propName, e.Message), ErrorNumbers.Error_InvalidIdentifier);
68                 }
69             }
70             if (error != null)
71                 error.PropertyName = propName;
72             return error;
73         }
74
75         internal static ValidationError ValidateNameProperty(string propName, IServiceProvider context, string identifier)
76         {
77             if (context == null)
78                 throw new ArgumentNullException("context");
79
80             ValidationError error = null;
81             if (identifier == null || identifier.Length == 0)
82                 error = new ValidationError(SR.GetString(SR.Error_PropertyNotSet, propName), ErrorNumbers.Error_PropertyNotSet);
83             else
84             {
85                 SupportedLanguages language = CompilerHelpers.GetSupportedLanguage(context);
86                 CodeDomProvider provider = CompilerHelpers.GetCodeDomProvider(language);
87
88                 if (language == SupportedLanguages.CSharp && identifier.StartsWith("@", StringComparison.Ordinal) ||
89                     language == SupportedLanguages.VB && identifier.StartsWith("[", StringComparison.Ordinal) && identifier.EndsWith("]", StringComparison.Ordinal) ||
90                     !provider.IsValidIdentifier(provider.CreateEscapedIdentifier(identifier)))
91                 {
92                     error = new ValidationError(SR.GetString(SR.Error_InvalidIdentifier, propName, SR.GetString(SR.Error_InvalidLanguageIdentifier, identifier)), ErrorNumbers.Error_InvalidIdentifier);
93                 }
94             }
95             if (error != null)
96                 error.PropertyName = propName;
97             return error;
98         }
99
100         internal static ValidationErrorCollection ValidateUniqueIdentifiers(Activity rootActivity)
101         {
102             if (rootActivity == null)
103                 throw new ArgumentNullException("rootActivity");
104
105             Hashtable identifiers = new Hashtable();
106             ValidationErrorCollection validationErrors = new ValidationErrorCollection();
107             Queue activities = new Queue();
108             activities.Enqueue(rootActivity);
109             while (activities.Count > 0)
110             {
111                 Activity activity = (Activity)activities.Dequeue();
112                 if (activity.Enabled)
113                 {
114                     if (identifiers.ContainsKey(activity.QualifiedName))
115                     {
116                         ValidationError duplicateError = new ValidationError(SR.GetString(SR.Error_DuplicatedActivityID, activity.QualifiedName), ErrorNumbers.Error_DuplicatedActivityID);
117                         duplicateError.PropertyName = "Name";
118                         duplicateError.UserData[typeof(Activity)] = activity;
119                         validationErrors.Add(duplicateError);
120                     }
121                     else
122                         identifiers.Add(activity.QualifiedName, activity);
123
124                     if (activity is CompositeActivity && ((activity.Parent == null) || !Helpers.IsCustomActivity(activity as CompositeActivity)))
125                     {
126                         foreach (Activity child in Helpers.GetAllEnabledActivities((CompositeActivity)activity))
127                             activities.Enqueue(child);
128                     }
129                 }
130             }
131
132             return validationErrors;
133
134         }
135         #endregion
136
137         #region Validation for Activity Ref order
138
139         internal static bool IsActivitySourceInOrder(Activity request, Activity response)
140         {
141             if (request.Parent == null)
142                 return true;
143             List<Activity> responsePath = new List<Activity>();
144             responsePath.Add(response);
145             Activity responseParent = response is CompositeActivity ? (CompositeActivity)response : response.Parent;
146             while (responseParent != null)
147             {
148                 responsePath.Add(responseParent);
149                 responseParent = responseParent.Parent;
150             }
151
152             Activity requestChild = request;
153             CompositeActivity requestParent = request is CompositeActivity ? (CompositeActivity)request : request.Parent;
154             while (requestParent != null && !responsePath.Contains(requestParent))
155             {
156                 requestChild = requestParent;
157                 requestParent = requestParent.Parent;
158             }
159
160             if (requestParent == requestChild)
161                 return true;
162
163             bool incorrectOrder = false;
164             int index = (responsePath.IndexOf(requestParent) - 1);
165             index = (index < 0) ? 0 : index; //sometimes parent gets added to the collection twice which causes index to be -1
166             Activity responseChild = responsePath[index];
167
168             if (requestParent == null || Helpers.IsAlternateFlowActivity(requestChild) || Helpers.IsAlternateFlowActivity(responseChild))
169                 incorrectOrder = true;
170             else
171             {
172                 for (int i = 0; i < requestParent.EnabledActivities.Count; i++)
173                 {
174                     if (requestParent.EnabledActivities[i] == requestChild)
175                         break;
176                     else if (requestParent.EnabledActivities[i] == responseChild)
177                     {
178                         incorrectOrder = true;
179                         break;
180                     }
181                 }
182             }
183             return !incorrectOrder;
184         }
185
186         #endregion
187
188         internal static ValidationErrorCollection ValidateObject(ValidationManager manager, object obj)
189         {
190             ValidationErrorCollection errors = new ValidationErrorCollection();
191             if (obj == null)
192                 return errors;
193
194             Type objType = obj.GetType();
195             if (!objType.IsPrimitive && (objType != typeof(string)))
196             {
197                 bool removeValidatedObjectCollection = false;
198                 Dictionary<int, object> validatedObjects = manager.Context[typeof(Dictionary<int, object>)] as Dictionary<int, object>;
199                 if (validatedObjects == null)
200                 {
201                     validatedObjects = new Dictionary<int, object>();
202                     manager.Context.Push(validatedObjects);
203                     removeValidatedObjectCollection = true;
204                 }
205
206                 try
207                 {
208                     if (!validatedObjects.ContainsKey(obj.GetHashCode()))
209                     {
210                         validatedObjects.Add(obj.GetHashCode(), obj);
211                         try
212                         {
213                             Validator[] validators = manager.GetValidators(objType);
214                             foreach (Validator validator in validators)
215                                 errors.AddRange(validator.Validate(manager, obj));
216                         }
217                         finally
218                         {
219                             validatedObjects.Remove(obj.GetHashCode());
220                         }
221                     }
222                 }
223                 finally
224                 {
225                     if (removeValidatedObjectCollection)
226                         manager.Context.Pop();
227                 }
228             }
229
230             return errors;
231         }
232
233         internal static ValidationErrorCollection ValidateActivity(ValidationManager manager, Activity activity)
234         {
235             ValidationErrorCollection errors = ValidationHelpers.ValidateObject(manager, activity);
236
237             foreach (ValidationError error in errors)
238             {
239                 if (!error.UserData.Contains(typeof(Activity)))
240                     error.UserData[typeof(Activity)] = activity;
241             }
242             return errors;
243         }
244
245         internal static ValidationErrorCollection ValidateProperty(ValidationManager manager, Activity activity, object obj, PropertyValidationContext propertyValidationContext)
246         {
247             return ValidateProperty(manager, activity, obj, propertyValidationContext, null);
248         }
249
250         internal static ValidationErrorCollection ValidateProperty(ValidationManager manager, Activity activity, object obj, PropertyValidationContext propertyValidationContext, object extendedPropertyContext)
251         {
252             if (manager == null)
253                 throw new ArgumentNullException("manager");
254             if (obj == null)
255                 throw new ArgumentNullException("obj");
256             if (propertyValidationContext == null)
257                 throw new ArgumentNullException("propertyValidationContext");
258
259             ValidationErrorCollection errors = new ValidationErrorCollection();
260
261             manager.Context.Push(activity);
262             manager.Context.Push(propertyValidationContext);
263             if (extendedPropertyContext != null)
264                 manager.Context.Push(extendedPropertyContext);
265             try
266             {
267                 errors.AddRange(ValidationHelpers.ValidateObject(manager, obj));
268             }
269             finally
270             {
271                 manager.Context.Pop();
272                 manager.Context.Pop();
273                 if (extendedPropertyContext != null)
274                     manager.Context.Pop();
275             }
276
277             return errors;
278         }
279     }
280 }