public async Task <T> GenerateProxy <T>(
            IHardwareRepresentation hardwareRepresentation,
            T hardwareObject,
            IProxyGenerationConfiguration configuration) where T : class
        {
            if (!hardwareRepresentation.SoftAssemblyPaths.Contains(hardwareObject.GetType().Assembly.Location))
            {
                throw new InvalidOperationException(
                          "The supplied type is not part of any assembly that this hardware representation was generated from.");
            }

            try
            {
                return(await
                       _host
                       .RunGet(scope => Task.Run(() => scope.Resolve <IProxyGenerator>().CreateCommunicationProxy(hardwareRepresentation, hardwareObject, configuration))));
            }
            catch (Exception ex) when(!ex.IsFatal())
            {
                var message =
                    "An error happened during generating the Hastlayer proxy for an object of the following type: " +
                    hardwareObject.GetType().FullName;
                await _host.Run <ILoggerService>(logger => Task.Run(() => logger.Error(ex, message)));

                throw new HastlayerException(message, ex);
            }
        }
Exemple #2
0
        public T CreateCommunicationProxy <T>(IHardwareRepresentation hardwareRepresentation, T target, IProxyGenerationConfiguration configuration) where T : class
        {
            var memberInvocationHandler = _memberInvocationHandlerFactory.CreateMemberInvocationHandler(hardwareRepresentation, target, configuration);

            if (typeof(T).IsInterface)
            {
                return(_proxyGenerator.CreateInterfaceProxyWithTarget(target, new MemberInvocationInterceptor(memberInvocationHandler)));
            }

            return(_proxyGenerator.CreateClassProxyWithTarget(target, new MemberInvocationInterceptor(memberInvocationHandler)));
        }
Exemple #3
0
 /// <summary>
 /// Gets the custom configuration if it exists or creates and adds it if it doesn't.
 /// </summary>
 /// <typeparam name="T">Type of the configuration object.</typeparam>
 /// <param name="key">Key where the custom configuration object is stored in the
 /// <see cref="IProxyGenerationConfiguration"/> instance.</param>
 /// <returns>The existing or newly created configuration object.</returns>
 public static T GetOrAddCustomConfiguration <T>(this IProxyGenerationConfiguration proxyGenerationConfiguration, string key)
     where T : new() =>
 proxyGenerationConfiguration.CustomConfiguration.GetOrAddCustomConfiguration <T>(key);
Exemple #4
0
        public MemberInvocationHandler CreateMemberInvocationHandler(
            IHardwareRepresentation hardwareRepresentation,
            object target,
            IProxyGenerationConfiguration configuration)
        {
            return(invocation =>
            {
                var methodAsynchronicity = GetMethodAsynchronicity(invocation);

                if (methodAsynchronicity == MethodAsynchronicity.AsyncFunction)
                {
                    throw new NotSupportedException("Only async methods that return a Task, not Task<T>, are supported.");
                }


                async Task invocationHandler()
                {
                    using (var workContext = _wca.CreateWorkContextScope())
                    {
                        // Although it says Method it can also be a property.
                        var memberFullName = invocation.Method.GetFullName();

                        var invocationContext = new MemberInvocationContext
                        {
                            Invocation = invocation,
                            MemberFullName = memberFullName,
                            HardwareRepresentation = hardwareRepresentation
                        };

                        var eventHandler = workContext.Resolve <IMemberInvocationEventHandler>();
                        eventHandler.MemberInvoking(invocationContext);

                        workContext.Resolve <IEnumerable <IMemberInvocationPipelineStep> >().InvokePipelineSteps(step =>
                        {
                            invocationContext.HardwareExecutionIsCancelled = step.CanContinueHardwareExecution(invocationContext);
                        });

                        if (!invocationContext.HardwareExecutionIsCancelled)
                        {
                            var hardwareMembers = hardwareRepresentation.HardwareDescription.HardwareEntryPointNamesToMemberIdMappings;
                            var memberNameAlternates = new HashSet <string>(hardwareMembers.Keys.SelectMany(member => member.GetMemberNameAlternates()));
                            if (!hardwareMembers.ContainsKey(memberFullName) && !memberNameAlternates.Contains(memberFullName))
                            {
                                invocationContext.HardwareExecutionIsCancelled = true;
                            }
                        }

                        if (invocationContext.HardwareExecutionIsCancelled)
                        {
                            invocation.Proceed();

                            if (methodAsynchronicity == MethodAsynchronicity.AsyncAction)
                            {
                                await(Task) invocation.ReturnValue;
                            }

                            return;
                        }

                        var communicationChannelName = configuration.CommunicationChannelName;
                        var deviceManifest = hardwareRepresentation.DeviceManifest;

                        if (string.IsNullOrEmpty(communicationChannelName))
                        {
                            communicationChannelName = deviceManifest.DefaultCommunicationChannelName;
                        }

                        if (!deviceManifest.SupportedCommunicationChannelNames.Contains(communicationChannelName))
                        {
                            throw new NotSupportedException(
                                "The configured communication channel \"" + communicationChannelName +
                                "\" is not supported by the current device.");
                        }

                        var memory = (SimpleMemory)invocation.Arguments.SingleOrDefault(argument => argument is SimpleMemory);
                        if (memory != null)
                        {
                            var memoryByteCount = (ulong)memory.CellCount * SimpleMemory.MemoryCellSizeBytes;
                            if (memoryByteCount > deviceManifest.AvailableMemoryBytes)
                            {
                                throw new InvalidOperationException(
                                    "The input is too large to fit into the device's memory: the input is " +
                                    memoryByteCount + " bytes, the available memory is " +
                                    deviceManifest.AvailableMemoryBytes + " bytes.");
                            }

                            SimpleMemory softMemory = null;

                            if (configuration.VerifyHardwareResults)
                            {
                                softMemory = new SimpleMemory(memory.CellCount);
                                var memoryBytes = new SimpleMemoryAccessor(memory).Get();
                                memoryBytes.CopyTo(new SimpleMemoryAccessor(softMemory).Get());

                                var memoryArgumentIndex = invocation.Arguments
                                                          .Select((argument, index) => new { Argument = argument, Index = index })
                                                          .Single(argument => argument.Argument is SimpleMemory)
                                                          .Index;
                                invocation.SetArgumentValue(memoryArgumentIndex, softMemory);

                                // This needs to happen before the awaited Execute() call below, otherwise the Task
                                // in ReturnValue wouldn't be the original one any more.
                                invocation.Proceed();

                                if (methodAsynchronicity == MethodAsynchronicity.AsyncAction)
                                {
                                    await(Task) invocation.ReturnValue;
                                }
                            }

                            // At this point we checked that the hardware entry point does have a mapping.
                            var memberId = hardwareRepresentation
                                           .HardwareDescription
                                           .HardwareEntryPointNamesToMemberIdMappings[memberFullName];
                            invocationContext.ExecutionInformation = await workContext
                                                                     .Resolve <ICommunicationServiceSelector>()
                                                                     .GetCommunicationService(communicationChannelName)
                                                                     .Execute(
                                memory,
                                memberId,
                                new HardwareExecutionContext {
                                ProxyGenerationConfiguration = configuration, HardwareRepresentation = hardwareRepresentation
                            });

                            if (configuration.VerifyHardwareResults)
                            {
                                var mismatches = new List <HardwareExecutionResultMismatchException.Mismatch>();

                                if (memory.CellCount != softMemory.CellCount)
                                {
                                    int overflowIndex = Math.Min(memory.CellCount, softMemory.CellCount);
                                    mismatches.Add(new HardwareExecutionResultMismatchException.LengthMismatch(
                                                       memory.CellCount,
                                                       softMemory.CellCount,
                                                       overflowIndex,
                                                       memory.CellCount > softMemory.CellCount ? memory.Read4Bytes(overflowIndex) : new byte[0],
                                                       softMemory.CellCount > memory.CellCount ? softMemory.Read4Bytes(overflowIndex) : new byte[0]));
                                }
                                else
                                {
                                    for (int i = 0; i < memory.CellCount; i++)
                                    {
                                        if (!memory.Read4Bytes(i).SequenceEqual(softMemory.Read4Bytes(i)))
                                        {
                                            mismatches.Add(new HardwareExecutionResultMismatchException.Mismatch(
                                                               i, memory.Read4Bytes(i), softMemory.Read4Bytes(i)));
                                        }
                                    }
                                }

                                if (mismatches.Any())
                                {
                                    throw new HardwareExecutionResultMismatchException(mismatches);
                                }
                            }
                        }
                        else
                        {
                            throw new NotSupportedException(
                                "Only SimpleMemory-using implementations are supported for hardware execution. The invocation didn't include a SimpleMemory argument.");
                        }

                        eventHandler.MemberExecutedOnHardware(invocationContext);
                    }
                }

                if (methodAsynchronicity == MethodAsynchronicity.AsyncAction)
                {
                    invocation.ReturnValue = invocationHandler();
                }
                else
                {
                    invocationHandler().Wait();
                }
            });
        }