/// <summary> /// Constructs an activity instance suitable for executing a local activity. /// </summary> /// <param name="client">The associated client.</param> /// <param name="invokeInfo">The activity invocation information.</param> /// <param name="contextId">The activity context ID or <c>null</c> for local activities.</param> /// <returns>The constructed activity.</returns> private static ActivityBase Create(CadenceClient client, ActivityInvokeInfo invokeInfo, long?contextId) { Covenant.Requires <ArgumentNullException>(client != null); var activity = (ActivityBase)(invokeInfo.Constructor.Invoke(noArgs)); activity.Initialize(client, invokeInfo.ActivityType, invokeInfo.ActivityMethod, client.DataConverter, contextId); return(activity); }
/// <summary> /// Registers an activity type. /// </summary> /// <param name="client">The associated client.</param> /// <param name="activityType">The activity type.</param> /// <param name="activityTypeName">The name used to identify the implementation.</param> /// <returns><c>true</c> if the activity was already registered.</returns> /// <exception cref="InvalidOperationException">Thrown if a different activity class has already been registered for <paramref name="activityTypeName"/>.</exception> internal static bool Register(CadenceClient client, Type activityType, string activityTypeName) { Covenant.Requires <ArgumentNullException>(client != null); CadenceHelper.ValidateActivityImplementation(activityType); activityTypeName = GetActivityTypeKey(client, activityTypeName); var constructInfo = new ActivityInvokeInfo(); constructInfo.ActivityType = activityType; constructInfo.Constructor = constructInfo.ActivityType.GetConstructor(noTypeArgs); if (constructInfo.Constructor == null) { throw new ArgumentException($"Activity type [{constructInfo.ActivityType.FullName}] does not have a default constructor."); } lock (syncLock) { if (nameToInvokeInfo.TryGetValue(activityTypeName, out var existingEntry)) { if (!object.ReferenceEquals(existingEntry.ActivityType, constructInfo.ActivityType)) { throw new InvalidOperationException($"Conflicting activity type registration: Activity type [{activityType.FullName}] is already registered for workflow type name [{activityTypeName}]."); } return(true); } else { nameToInvokeInfo[activityTypeName] = constructInfo; return(false); } } }
/// <summary> /// Returns the <see cref="ActivityInvokeInfo"/> for any activity type and activity type name. /// </summary> /// <param name="activityType">The targetr activity type.</param> /// <param name="activityTypeName">The target activity type name.</param> /// <returns>The <see cref="ActivityInvokeInfo"/>.</returns> private static ActivityInvokeInfo GetActivityInvokeInfo(Type activityType, string activityTypeName) { Covenant.Requires <ArgumentNullException>(activityType != null); Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(activityTypeName)); var info = new ActivityInvokeInfo(); // Locate the constructor. info.Constructor = activityType.GetConstructor(noTypeArgs); if (info.Constructor == null) { throw new ArgumentException($"Activity type [{activityType.FullName}] does not have a default constructor."); } // Locate the target method. Note that the activity type name will be // formatted like: // // CLIENT-ID::TYPE-NAME // or CLIENT-ID::TYPE-NAME::METHOD-NAME var activityTypeNameParts = activityTypeName.Split(CadenceHelper.ActivityTypeMethodSeparator.ToCharArray(), 3); var activityMethodName = (string)null; Covenant.Assert(activityTypeNameParts.Length >= 2); if (activityTypeNameParts.Length > 2) { activityMethodName = activityTypeNameParts[2]; } if (string.IsNullOrEmpty(activityMethodName)) { activityMethodName = null; } foreach (var method in activityType.GetMethods(BindingFlags.Public | BindingFlags.Instance)) { var activityMethodAttribute = method.GetCustomAttribute <ActivityMethodAttribute>(); if (activityMethodAttribute == null) { continue; } var name = activityMethodAttribute.Name; if (string.IsNullOrEmpty(name)) { name = null; } if (name == activityMethodName) { info.ActivityMethod = method; break; } } if (info.ActivityMethod == null) { throw new ArgumentException($"Activity type [{activityType.FullName}] does not have an entry point method tagged with [ActivityMethod(Name = \"{activityMethodName}\")]."); } return(info); }