예제 #1
0
        /// <summary>
        /// Performs a subscription to a remote publisher for a local subscriber<br />#
        /// In this method, the remote subscription is completed
        /// </summary>
        internal static void SubscribeToRemotePublisher <T>(RemoteSubscriptionHandle handle, object subscriberInstance, Action <T, SubscriptionHandle> newDataCallBack, DataModifyPolicy policy, Func <T, bool> evaluateTemplateObject, Action <Type, SubscriptionHandle> subscriptionCallback)
        {
            _log.DebugFormat("Completing subscription to remote publisher {0} on node {1},handle: {2}, type: {3}",
                             handle.PublisherId, handle.PublisherNodeID, handle, typeof(T).Name);
            //TODO template object

            //Create a stub
            Stub <T> s = new Stub <T> {
                DataType = typeof(T), Handle = handle
            };

            if (
                (EllaModel.Instance.GetActivePublishers().Where(p => p.Instance is Stub && (p.Instance as Stub).Handle == handle)).Any())
            {
                _log.DebugFormat("Avoiding double subscription for handle {0}. Anready an active stub available.", handle);
                return;
            }
            var publishesAttribute = (PublishesAttribute)s.GetType().GetCustomAttributes(typeof(PublishesAttribute), false).First();

            if (handle is MulticastRemoteSubscriptionhandle)
            {
                _log.DebugFormat("{0} is potential multicast subscription, opening multicast port", handle);
                MulticastRemoteSubscriptionhandle mh = handle as MulticastRemoteSubscriptionhandle;
                Networking.ConnectToMulticast(mh.IpAddress, mh.Port);
                RemoteSubscriptionHandle h = new RemoteSubscriptionHandle()
                {
                    PublisherNodeID       = handle.PublisherNodeID,
                    PublisherId           = handle.PublisherId,
                    SubscriptionReference = handle.SubscriptionReference,
                    EventID          = handle.EventID,
                    SubscriberNodeID = handle.SubscriberNodeID
                };
                s.Handle = h;
            }
            Start.Publisher(s);
            Event ev = new Event
            {
                Publisher   = s,
                EventDetail = publishesAttribute
            };

            handle.SubscriberId = EllaModel.Instance.GetSubscriberId(subscriberInstance);
            Subscription sub = new Subscription(subscriberInstance, ev, newDataCallBack.Method, newDataCallBack.Target)
            {
                Handle = s.Handle, DataType = typeof(T)
            };


            EllaModel.Instance.AddSubscription(sub);
            var sanity = EllaModel.Instance.CheckSubscriptionSanity();

            if (sanity > 0)
            {
                _log.WarnFormat("Subscription sanity restored. removed {0} subscriptions", sanity);
            }

            if (subscriptionCallback != null)
            {
                _log.DebugFormat("Found subscription callback for {0}, notifying subscriber", handle);
                subscriptionCallback(typeof(T), sub.Handle);
            }
            else
            {
                _log.DebugFormat("Subscription callback for {0} was null, not notifying subscriber", handle);
            }
        }
예제 #2
0
        /// <summary>
        /// Does the local subscription.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="subscriberInstance">The subscriber instance.</param>
        /// <param name="newDataCallback">The new data callback.</param>
        /// <param name="evaluateTemplateObject">The evaluate template object.</param>
        /// <param name="subscriptionCallback">The subscription callback.</param>
        /// <param name="policy">The modification policy.</param>
        /// <exception cref="System.ArgumentException">subscriberInstance must be a valid subscriber</exception>
        /// <exception cref="IllegalAttributeUsageException"></exception>
        internal static void DoLocalSubscription <T>(object subscriberInstance, Action <T, SubscriptionHandle> newDataCallback, Func <T, bool> evaluateTemplateObject, Action <Type, SubscriptionHandle> subscriptionCallback, DataModifyPolicy policy)
        {
            /*
             * find all matching events from currently active publishers
             * check if subscriber instace is valid subscriber
             * hold a list of subscriptions
             */
            if (!Is.Subscriber(subscriberInstance.GetType()))
            {
                _log.ErrorFormat("{0} is not a valid subscriber", subscriberInstance.GetType().ToString());
                throw new ArgumentException("subscriberInstance must be a valid subscriber");
            }
            var matches = EllaModel.Instance.ActiveEvents.FirstOrDefault(g => g.Key == typeof(T));

            if (matches != null)
            {
                Dictionary <SubscriptionHandle, SubscriptionHandle> correlatedEvents = new Dictionary <SubscriptionHandle, SubscriptionHandle>();
                MethodBase associateMethod = ReflectionUtils.GetAttributedMethod(subscriberInstance.GetType(), typeof(AssociateAttribute));

                _log.DebugFormat("Found {0} matches for subsription to {1}", matches.Count(), typeof(T));
                foreach (var m in matches)
                {
                    if (m.Publisher == subscriberInstance)
                    {
                        _log.DebugFormat("Not subscribing {0} for itself", subscriberInstance);
                        continue;
                    }
                    object templateObject = Create.TemplateObject(m.Publisher, m.EventDetail.ID);
                    T      template       = templateObject != null ? (T)templateObject : default(T);
                    //SubscriptionID in the handle is set automatically when assigning it to a subscription
                    SubscriptionHandle handle = new SubscriptionHandle
                    {
                        EventID      = m.EventDetail.ID,
                        PublisherId  = EllaModel.Instance.GetPublisherId(m.Publisher),
                        SubscriberId = EllaModel.Instance.GetSubscriberId(subscriberInstance)
                    };

                    var subscription = new Subscription
                    {
                        Event          = m,
                        Subscriber     = subscriberInstance,
                        CallbackMethod = newDataCallback.Method,
                        CallbackTarget = newDataCallback.Target,
                        Handle         = handle,
                        DataType       = typeof(T),
                        ModifyPolicy   = policy
                    };



                    if (templateObject == null || evaluateTemplateObject(template))
                    {
                        if (!EllaModel.Instance.ContainsSubscriptions(subscription))
                        {
                            _log.InfoFormat("Subscribing {0} to {1} for type {2}", subscriberInstance, m.Publisher,
                                            m.EventDetail.DataType);
                            EllaModel.Instance.AddSubscription(subscription);
                            if (subscriptionCallback != null)
                            {
                                subscriptionCallback(typeof(T), subscription.Handle);
                            }
                            NotifyPublisher(subscription.Event, subscription.Handle);
                            if (associateMethod != null)
                            {
                                var correlations = EllaModel.Instance.GetEventCorrelations(handle.EventHandle);
                                if (correlations != null)
                                {
                                    foreach (
                                        SubscriptionHandle correlationHandle in
                                        correlations.Select(correlation => new SubscriptionHandle()
                                    {
                                        EventHandle = correlation,
                                    }))
                                    {
                                        correlationHandle.SubscriberId =
                                            handle.SubscriberId;
                                        correlatedEvents.Add(handle, correlationHandle);
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        _log.DebugFormat("Templateobject from {0} was rejected by {1}", m.Publisher, subscriberInstance);
                    }
                }
                if (associateMethod != null)
                {
                    if (associateMethod.GetParameters().Count() != 2 || associateMethod.GetParameters().Any(p => p.ParameterType != typeof(SubscriptionHandle)))
                    {
                        throw new IllegalAttributeUsageException(String.Format("Method {0} attributed as Associate has invalid parameters (count or type)", associateMethod));
                    }
                    foreach (var handlePair in correlatedEvents)
                    {
                        //Only do this if subscriber is subscribed to both events
                        if (EllaModel.Instance.FilterSubscriptions(s =>
                                                                   Equals(s.Handle.EventHandle,
                                                                          handlePair.Value.EventHandle) &&
                                                                   s.Subscriber == subscriberInstance).Any())
                        {
                            associateMethod.Invoke(subscriberInstance,
                                                   new object[] { handlePair.Key, handlePair.Value });
                        }
                    }
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Subscribes the <paramref name="subscriberInstance" /> to any event matching <typeparamref name="T" /> as event data type
        /// </summary>
        /// <typeparam name="T">The type to subscribe to</typeparam>
        /// <param name="subscriberInstance">The instance of a subscriber to be subscribed to the event</param>
        /// <param name="newDataCallback">A callback method acceptiong <typeparamref name="T" /> as argument, which will be called when new data from publishers is available</param>
        /// <param name="policy">The data modify policy, default is <see cref="DataModifyPolicy.NoModify" /></param>
        /// <param name="evaluateTemplateObject">Pass a Func to subscribe using template objects. If no Func is given, <paramref name="subscriberInstance" /> will be subscribed to every event with matching <typeparamref name="T" />.<br />
        /// As an alternative, a <paramref name="evaluateTemplateObject" /> can be provided to request templates for the data to be published from every single publisher.</param>
        /// <param name="forbidRemote">if set to <c>true</c> no remote publishers will be considered.</param>
        /// <param name="subscriptionCallback">A callback method used to notify the subscriber of a new subscription. It passes a <seealso cref="SubscriptionHandle"/> instance used to identify the 1:1 relation between one publisher event and one subscriber</param>
        /// <exception cref="System.ArgumentException">subscriberInstance must be a valid subscriber</exception>
        public static void To <T>(object subscriberInstance, Action <T, SubscriptionHandle> newDataCallback, DataModifyPolicy policy = DataModifyPolicy.NoModify, Func <T, bool> evaluateTemplateObject = null, bool forbidRemote = false, Action <Type, SubscriptionHandle> subscriptionCallback = null)
        {
            _log.DebugFormat("Subscribing {0} to type {1} {2}", subscriberInstance, typeof(T),
                             (evaluateTemplateObject != null ? "with template object" : string.Empty));

            EllaModel.Instance.AddActiveSubscriber(subscriberInstance);
            if (!forbidRemote)
            {
                if (Networking.IsRunning)
                {
                    Func <T, bool> eval = evaluateTemplateObject;
                    Action <RemoteSubscriptionHandle> callback =
                        handle => SubscriptionController.SubscribeToRemotePublisher(handle, subscriberInstance, newDataCallback, policy,
                                                                                    eval, subscriptionCallback);
                    Networking.SubscribeToRemoteHost <T>(callback);
                }
            }
            if (evaluateTemplateObject == null)
            {
                evaluateTemplateObject = (o => true);
            }


            SubscriptionRequest sr = new SubscriptionRequest()
            {
                SubscriberInstance = subscriberInstance,
                RequestedType      = typeof(T)
            };

            sr.SubscriptionCall = () => SubscriptionController.DoLocalSubscription <T>(subscriberInstance, newDataCallback,
                                                                                       evaluateTemplateObject, subscriptionCallback, policy);
            EllaModel.Instance.AddSubscriptionRequest(sr);
            SubscriptionController.DoLocalSubscription(subscriberInstance, newDataCallback, evaluateTemplateObject, subscriptionCallback, policy);
        }