Ejemplo n.º 1
0
        /// <summary>
        /// Store an object into storage, with the current node as the owner.
        /// </summary>
        /// <param name="id">
        /// The unique identifier of the object.
        /// </param>
        /// <param name="data">
        /// The object itself.
        /// </param>
        public void Store(string id, object data)
        {
            this.AssertBound();

            var objectStorage = this.GetService <IObjectStorage>();

            objectStorage.Put(new LiveEntry {
                Key = ID.NewHash(id), Value = data, Owner = this.Self
            });
        }
Ejemplo n.º 2
0
        public object GetProperty(string id, string property)
        {
            this.AssertBound();

            var messageConstructor       = this.GetService <IMessageConstructor>();
            var objectWithTypeSerializer = this.GetService <IObjectWithTypeSerializer>();
            var automaticRetry           = this.GetService <IAutomaticRetry>();

            var entry = this.GetHandlerAndObjectByID(id);
            var obj   = entry.Value;

            if (this.Architecture == Architecture.PeerToPeer && entry.Owner != this.Self)
            {
                // We need to request the value from the node that owns it.
                var getMessage = messageConstructor.ConstructGetPropertyMessage(ID.NewHash(id), property);

                var message = automaticRetry.SendWithRetry(
                    entry.ClientHandler,
                    getMessage,
                    x => x.Type == MessageType.GetPropertyResult && x.GetPropertyMessageID == getMessage.ID,
                    this.Timeout,
                    this.Retries);

                return(objectWithTypeSerializer.Deserialize(message.GetPropertyResult));
            }

            if (this.Architecture == Architecture.ServerClient)
            {
                if (!this.IsServer && this.Caching != Caching.PushOnChange)
                {
                    // We are the client, but we need to request the value
                    // from the server.
                    var getMessage = messageConstructor.ConstructGetPropertyMessage(ID.NewHash(id), property);

                    var message = automaticRetry.SendWithRetry(
                        entry.ClientHandler,
                        getMessage,
                        x => x.Type == MessageType.GetPropertyResult && x.GetPropertyMessageID == getMessage.ID,
                        this.Timeout,
                        this.Retries);

                    return(objectWithTypeSerializer.Deserialize(message.GetPropertyResult));
                }
            }

            var mi = obj.GetType().GetMethod("get_" + property + "__Distributed0", BindingFlagsCombined.All);

            if (mi == null)
            {
                throw new MissingMethodException(obj.GetType().FullName, "get_" + property + "__Distributed0");
            }

            return(DpmEntrypoint.InvokeDynamic(obj.GetType(), mi, obj, new Type[0], new object[] { }));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Fetch an object from storage.
        /// </summary>
        /// <param name="id">
        /// The unique identifier of the object.
        /// </param>
        /// <returns>
        /// The object, or null if none was found.
        /// </returns>
        public object Fetch(string id)
        {
            this.AssertBound();

            var objectLookup = this.GetService <IObjectLookup>();

            var entry = objectLookup.GetFirst(ID.NewHash(id), 60000);

            if (entry == null)
            {
                return(null);
            }

            return(entry.Value);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Retrieve the client handler, owner and live object based on the
        /// specified object's ID.
        /// </summary>
        /// <param name="id">
        /// The id of the object to retrieve.
        /// </param>
        /// <returns>
        /// The <see cref="ObjectEntry"/>.
        /// </returns>
        /// <exception cref="NullReferenceException">
        /// The object could not be found.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// The client owning the object could not be found.
        /// </exception>
        private ObjectEntry GetHandlerAndObjectByID(string id)
        {
            var objectLookup = this.GetService <IObjectLookup>();
            var clientLookup = this.GetService <IClientLookup>();

            var entry = objectLookup.GetFirst(ID.NewHash(id), 60000);

            if (entry == null)
            {
                throw new NullReferenceException();
            }

            var clientHandler = clientLookup.Lookup(entry.Owner.IPEndPoint);

            if (clientHandler == null)
            {
                throw new InvalidOperationException();
            }

            return(new ObjectEntry {
                ClientHandler = clientHandler, Owner = entry.Owner, Value = entry.Value
            });
        }
Ejemplo n.º 5
0
        public void SetProperty(string id, string property, object value)
        {
            this.AssertBound();

            var objectStorage      = this.GetService <IObjectStorage>();
            var clientLookup       = this.GetService <IClientLookup>();
            var messageConstructor = this.GetService <IMessageConstructor>();
            var automaticRetry     = this.GetService <IAutomaticRetry>();

            var entry = this.GetHandlerAndObjectByID(id);
            var obj   = entry.Value;

            var mi = obj.GetType().GetMethod("set_" + property + "__Distributed0", BindingFlagsCombined.All);

            if (mi == null)
            {
                throw new MissingMethodException(obj.GetType().FullName, "set_" + property + "__Distributed0");
            }

            if (this.Architecture == Architecture.PeerToPeer)
            {
                if (entry.Owner == this.Self)
                {
                    DpmEntrypoint.InvokeDynamic(obj.GetType(), mi, obj, new Type[0], new[] { value });
                    objectStorage.UpdateOrPut(new LiveEntry {
                        Key = ID.NewHash(id), Value = obj, Owner = this.Self
                    });
                    return;
                }

                var clientHandler      = clientLookup.Lookup(entry.Owner.IPEndPoint);
                var setPropertyMessage = messageConstructor.ConstructSetPropertyMessage(ID.NewHash(id), property, value);

                automaticRetry.SendWithRetry(
                    clientHandler,
                    setPropertyMessage,
                    x =>
                    x.Type == MessageType.SetPropertyConfirmation && x.SetPropertyMessageID == setPropertyMessage.ID,
                    this.Timeout,
                    this.Retries);

                return;
            }

            if (this.Architecture == Architecture.ServerClient)
            {
                // If we are a client, we can't set properties.
                if (!this.IsServer)
                {
                    throw new MemberAccessException("Only servers may set the '" + property + "' property.");
                }

                DpmEntrypoint.InvokeDynamic(obj.GetType(), mi, obj, new Type[0], new[] { value });
                objectStorage.UpdateOrPut(new LiveEntry {
                    Key = ID.NewHash(id), Value = obj, Owner = this.Self
                });

                if (this.Caching == Caching.PushOnChange)
                {
                    // We need to push the new value out to clients.
                    foreach (var client in clientLookup.GetAll().Where(x => !object.Equals(x.Key, this.Self.IPEndPoint)))
                    {
                        client.Value.Send(
                            messageConstructor.ConstructSetPropertyMessage(ID.NewHash(id), property, value));
                    }
                }

                return;
            }

            throw new NotSupportedException();
        }
Ejemplo n.º 6
0
        public object Invoke(string id, string method, Type[] targs, object[] args)
        {
            this.AssertBound();

            var messageConstructor       = this.GetService <IMessageConstructor>();
            var objectWithTypeSerializer = this.GetService <IObjectWithTypeSerializer>();
            var automaticRetry           = this.GetService <IAutomaticRetry>();

            var entry = this.GetHandlerAndObjectByID(id);
            var obj   = entry.Value;

            if (this.Architecture == Architecture.PeerToPeer)
            {
                // In peer-to-peer modes, methods are always invoked locally.
                var mi = obj.GetType().GetMethod(method, BindingFlagsCombined.All);
                if (mi == null)
                {
                    throw new MissingMethodException(obj.GetType().FullName, method);
                }

                return(DpmEntrypoint.InvokeDynamic(obj.GetType(), mi, obj, targs, args));
            }

            if (this.Architecture == Architecture.ServerClient)
            {
                if (this.IsServer)
                {
                    // The server is always permitted to call methods.
                    var mi = obj.GetType().GetMethod(method, BindingFlagsCombined.All);
                    if (mi == null)
                    {
                        throw new MissingMethodException(obj.GetType().FullName, method);
                    }

                    return(DpmEntrypoint.InvokeDynamic(obj.GetType(), mi, obj, targs, args));
                }
                else
                {
                    // We must see if the client is permitted to call the specified method.
                    var mi = obj.GetType()
                             .GetMethod(method.Substring(0, method.IndexOf("__Distributed0", System.StringComparison.Ordinal)), BindingFlagsCombined.All);
                    if (mi == null)
                    {
                        throw new MissingMethodException(obj.GetType().FullName, method);
                    }

                    if (mi.GetCustomAttributes(typeof(ClientIgnorableAttribute), false).Count() != 0)
                    {
                        return(null);
                    }

                    if (!mi.GetCustomAttributes(typeof(ClientCallableAttribute), false).Any())
                    {
                        throw new MemberAccessException(
                                  "The method '" + method + "' is not accessible to client machines.");
                    }

                    // If we get to here, then we're permitted to call the method, but we still need
                    // to remote it to the server.
                    var invokeMessage = messageConstructor.ConstructInvokeMessage(ID.NewHash(id), method, targs, args);

                    var message = automaticRetry.SendWithRetry(
                        entry.ClientHandler,
                        invokeMessage,
                        x => x.Type == MessageType.InvokeResult && x.InvokeMessageID == invokeMessage.ID,
                        this.Timeout,
                        this.Retries);

                    return(objectWithTypeSerializer.Deserialize(message.InvokeResult));
                }
            }

            throw new NotSupportedException();
        }