Example #1
0
        /// <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);
        }
Example #2
0
        /// <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);
                }
            }
        }
Example #3
0
        /// <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);
        }