1 // ---------------------------------------------------------------------------
2 // Copyright (C) 2006 Microsoft Corporation All Rights Reserved
3 // ---------------------------------------------------------------------------
4 
5 #define CODE_ANALYSIS
6 using System.CodeDom;
7 using System.Collections;
8 using System.ComponentModel.Design.Serialization;
9 using System.Diagnostics.CodeAnalysis;
10 using System.Globalization;
11 using System.IO;
12 using System.Workflow.ComponentModel;
13 using System.Workflow.ComponentModel.Compiler;
14 using System.Workflow.ComponentModel.Design;
15 using System.Workflow.ComponentModel.Serialization;
16 using System.Xml;
17 using System.Reflection;
18 using System.Diagnostics;
19 using System.Workflow.Activities.Common;
20 
21 namespace System.Workflow.Activities.Rules
22 {
23     internal static class ConditionHelper
24     {
GetContextType(ITypeProvider typeProvider, Activity currentActivity)25         internal static Type GetContextType(ITypeProvider typeProvider, Activity currentActivity)
26         {
27             Type contextType = null;
28             string className = String.Empty;
29             Activity rootActivity = null;
30 
31             if (Helpers.IsActivityLocked(currentActivity))
32             {
33                 rootActivity = Helpers.GetDeclaringActivity(currentActivity);
34             }
35             else
36             {
37                 rootActivity = Helpers.GetRootActivity(currentActivity);
38             }
39 
40             if (rootActivity != null)
41             {
42                 className = rootActivity.GetValue(WorkflowMarkupSerializer.XClassProperty) as string;
43                 if (!String.IsNullOrEmpty(className))
44                     contextType = typeProvider.GetType(className, false);
45 
46                 if (contextType == null)
47                     contextType = typeProvider.GetType(rootActivity.GetType().FullName);
48 
49                 // If all else fails (likely, we don't have a type provider), it's the root activity type.
50                 if (contextType == null)
51                     contextType = rootActivity.GetType();
52             }
53 
54             return contextType;
55         }
56 
57         /// <summary>
58         /// Is type a nullable value type (e.g. double?)?
59         /// </summary>
60         /// <param name="type"></param>
61         /// <returns></returns>
IsNullableValueType(Type type)62         internal static bool IsNullableValueType(Type type)
63         {
64             return ((type.IsValueType) && (type.IsGenericType) && (type.GetGenericTypeDefinition().Equals(typeof(Nullable<>))));
65         }
66 
67         /// <summary>
68         /// Is type a standard value type (i.e. not Nullable)?
69         /// </summary>
70         /// <param name="type"></param>
71         /// <returns></returns>
IsNonNullableValueType(Type type)72         internal static bool IsNonNullableValueType(Type type)
73         {
74             return ((type.IsValueType) && (!type.IsGenericType) && (type != typeof(string)));
75         }
76 
CloneObject(object original)77         internal static object CloneObject(object original)
78         {
79             if (original == null)
80                 return null;
81 
82             if (original.GetType().IsValueType)
83                 return original;
84 
85             ICloneable cloneable = original as ICloneable;
86             if (cloneable != null)
87                 return cloneable.Clone();
88 
89             string message = string.Format(CultureInfo.CurrentCulture, Messages.NotCloneable, original.GetType().FullName);
90             throw new NotSupportedException(message);
91         }
92 
CloneUserData(CodeObject original, CodeObject result)93         internal static void CloneUserData(CodeObject original, CodeObject result)
94         {
95             // clone UserData, if possible
96             foreach (object key in original.UserData.Keys)
97             {
98                 object newKey = CloneObject(key);
99                 object newValue = CloneObject(original.UserData[key]);
100                 result.UserData.Add(newKey, newValue);
101             }
102         }
103 
104         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
Load_Rules_DT(IServiceProvider serviceProvider, DependencyObject activity)105         internal static RuleDefinitions Load_Rules_DT(IServiceProvider serviceProvider, DependencyObject activity)
106         {
107             RuleDefinitions rules = (RuleDefinitions)activity.GetValue(RuleDefinitions.RuleDefinitionsProperty);
108             if (rules == null)
109             {
110                 WorkflowDesignerLoader loader = (WorkflowDesignerLoader)serviceProvider.GetService(typeof(WorkflowDesignerLoader));
111                 if (loader != null)
112                 {
113                     string rulesFileName = string.Empty;
114                     if (!string.IsNullOrEmpty(loader.FileName))
115                         rulesFileName = Path.Combine(Path.GetDirectoryName(loader.FileName), Path.GetFileNameWithoutExtension(loader.FileName));
116                     rulesFileName += ".rules";
117 
118                     try
119                     {
120                         using (TextReader ruleFileReader = loader.GetFileReader(rulesFileName))
121                         {
122                             if (ruleFileReader == null)
123                             {
124                                 rules = new RuleDefinitions();
125                             }
126                             else
127                             {
128                                 using (XmlReader xmlReader = XmlReader.Create(ruleFileReader))
129                                     rules = new WorkflowMarkupSerializer().Deserialize(xmlReader) as RuleDefinitions;
130                             }
131                         }
132                     }
133                     catch (Exception)
134                     {
135                         rules = new RuleDefinitions();
136                         //
137                     }
138                 }
139                 activity.SetValue(RuleDefinitions.RuleDefinitionsProperty, rules);
140             }
141             return rules;
142         }
143 
Flush_Rules_DT(IServiceProvider serviceProvider, Activity activity)144         internal static void Flush_Rules_DT(IServiceProvider serviceProvider, Activity activity)
145         {
146             RuleDefinitions rules = (RuleDefinitions)activity.GetValue(RuleDefinitions.RuleDefinitionsProperty);
147             if (rules != null)
148             {
149                 WorkflowDesignerLoader loader = (WorkflowDesignerLoader)serviceProvider.GetService(typeof(WorkflowDesignerLoader));
150                 if (loader != null)
151                 {
152                     string rulesFileName = string.Empty;
153                     if (!string.IsNullOrEmpty(loader.FileName))
154                         rulesFileName = Path.Combine(Path.GetDirectoryName(loader.FileName), Path.GetFileNameWithoutExtension(loader.FileName));
155                     rulesFileName += ".rules";
156 
157                     using (TextWriter ruleFileWriter = loader.GetFileWriter(rulesFileName))
158                     {
159                         if (ruleFileWriter != null)
160                         {
161                             using (XmlWriter xmlWriter = Helpers.CreateXmlWriter(ruleFileWriter))
162                             {
163                                 DesignerSerializationManager designerSerializationManager = new DesignerSerializationManager(serviceProvider);
164                                 using (designerSerializationManager.CreateSession())
165                                 {
166                                     new WorkflowMarkupSerializer().Serialize(designerSerializationManager, xmlWriter, rules);
167                                 }
168                             }
169 
170                         }
171                     }
172                 }
173             }
174         }
175 
Load_Rules_RT(Activity declaringActivity)176         internal static RuleDefinitions Load_Rules_RT(Activity declaringActivity)
177         {
178             RuleDefinitions rules = declaringActivity.GetValue(RuleDefinitions.RuleDefinitionsProperty) as RuleDefinitions;
179             if (rules == null)
180             {
181                 rules = ConditionHelper.GetRuleDefinitionsFromManifest(declaringActivity.GetType());
182                 if (rules != null)
183                     declaringActivity.SetValue(RuleDefinitions.RuleDefinitionsProperty, rules);
184             }
185             return rules;
186         }
187 
188         // To improve performance, cache the RuleDefinitions deserialized from
189         // .rules resources keyed by the type of activity.
190         static Hashtable cloneableOrNullRulesResources = new Hashtable();
191         // It is unfortunate, however, that cloning might not always succeed, we will keep them here.
192         static Hashtable uncloneableRulesResources = new Hashtable();
193 
GetRuleDefinitionsFromManifest(Type workflowType)194         internal static RuleDefinitions GetRuleDefinitionsFromManifest(Type workflowType)
195         {
196             if (workflowType == null)
197                 throw new ArgumentNullException("workflowType");
198 
199             RuleDefinitions rules = null;
200 
201             if (cloneableOrNullRulesResources.ContainsKey(workflowType))
202             {
203                 rules = (RuleDefinitions)cloneableOrNullRulesResources[workflowType];
204                 if (rules != null)
205                 {
206                     // This should always succeed, since it is coming out of the cloneable cache
207                     rules = rules.Clone();
208                 }
209             }
210             else
211             {
212                 string resourceName = workflowType.Name + ".rules";
213                 Stream stream = workflowType.Module.Assembly.GetManifestResourceStream(workflowType, resourceName);
214 
215                 // Try just the .rules file name. This is needed for wfc.exe compilation scenarios.
216                 if (stream == null)
217                     stream = workflowType.Module.Assembly.GetManifestResourceStream(resourceName);
218 
219                 if (stream != null)
220                 {
221                     using (StreamReader reader = new StreamReader(stream))
222                     {
223                         using (XmlReader xmlReader = XmlReader.Create(reader))
224                             rules = new WorkflowMarkupSerializer().Deserialize(xmlReader) as RuleDefinitions;
225                     }
226                 }
227                 // Don't know yet whether 'rules' is cloneable, give it a try
228                 if (!uncloneableRulesResources.ContainsKey(workflowType))
229                 {
230                     try
231                     {
232                         RuleDefinitions originalRules = rules;
233                         if (rules != null)
234                         {
235                             rules = rules.Clone();
236                         }
237                         lock (cloneableOrNullRulesResources)
238                         {
239                             cloneableOrNullRulesResources[workflowType] = originalRules;
240                         }
241                     }
242                     catch (Exception)
243                     {
244                         lock (uncloneableRulesResources)
245                         {
246                             uncloneableRulesResources[workflowType] = null;
247                         }
248                     }
249                 }
250             }
251             return rules;
252         }
253     }
254 
255     internal static class EnumHelper
256     {
257         [SuppressMessage("Microsoft.Performance", "CA1803:AvoidCostlyCallsWherePossible")]
GetUnderlyingType(Type type)258         public static Type GetUnderlyingType(Type type)
259         {
260             Type underlyingType = typeof(int);
261             if (type.GetType().FullName.Equals("System.Workflow.ComponentModel.Compiler.DesignTimeType", StringComparison.Ordinal))// designTimeType = type as System.Workflow.ComponentModel.Compiler.DesignTimeType;
262             {
263                 //this is a design time type, need to get the enum type data out of it
264                 MethodInfo methodInfo = type.GetType().GetMethod("GetEnumType");
265                 Debug.Assert(methodInfo != null, "Missing GetEnumType method on the DesignTimeType!");
266                 if (methodInfo != null)
267                 {
268                     Type result = methodInfo.Invoke(type, new object[0]) as Type;
269                     underlyingType = (result != null) ? result : underlyingType;
270                 }
271             }
272             else
273             {
274                 underlyingType = Enum.GetUnderlyingType(type);
275             }
276 
277             return underlyingType;
278         }
279     }
280 }
281