/// <summary> /// Gesture that deploys an upgradeable service. The result is a service that implements the API defined /// in <typeparamref name="T"/>, but when it gets a special upgrade message, turns into a service that /// implements the API defined by <typeparamref name="T2"/>. /// The upgrade happens by creating an instance of the type <typeparamref name="Z2"/> and passing to its /// constructor the existing service instance so it can migrate over any needed state from it. /// </summary> /// <typeparam name="T">The interface that defines the API of the deployed service.</typeparam> /// <typeparam name="T2">The interface that defines the API of the service after it has been upgraded.</typeparam> /// <typeparam name="Z2"> /// The type of the class that implements <typeparamref name="T2"/> and which has a unary /// constructor that takes an argument of type <see cref="Immortal"/>. /// </typeparam> /// <param name="serviceName"></param> /// <param name="instance">The instance to deploy. It must implement <typeparamref name="T"/>.</param> /// <param name="receivePort">The port number on which it listens for messages from Ambrosia.</param> /// <param name="sendPort">The port number which the service uses to send messages to Ambrosia.</param> /// <returns></returns> public static IDisposable Deploy <T, T2, Z2>(string serviceName, Immortal instance, int receivePort, int sendPort) where T2 : T where Z2 : Immortal, T2 // *and* Z2 has a ctor that takes a Immortal as a parameter { var typeOfT = typeof(T); if (!typeOfT.IsInterface) { throw new ArgumentException($"The type '{typeOfT.Name}' must be an interface."); } if (!typeof(T2).IsInterface) { throw new ArgumentException($"The type '{typeof(T2).Name}' must be an interface."); } var immortalType = instance.GetType(); if (!typeof(IEmpty).IsAssignableFrom(typeOfT) && !immortalType.GetInterfaces().Any(i => i.Equals(typeOfT) || i.IsSubclassOf(typeOfT))) { throw new ArgumentException($"The instance to be deployed is of type '{immortalType.Name}' does not implement the type {typeOfT.Name}."); } // This can't go in a type constraint, but Z2 must have a ctor that takes the subtype of Immortal // that the instance is (i.e., its dynamic type). var ctor = typeof(Z2).GetConstructor(new Type[] { instance.GetType(), }); if (ctor == null) { throw new ArgumentException($"The type parameter Z2 was instantiated with the type '{typeof(Z2).Name}' that does not have a public constructor which takes a {typeof(Immortal).Name} as its only parameter."); } // Generate server Ambrosia instance and cache it. Use type parameter T to tell the generation what // interface to generate a proxy for. Immortal.Dispatcher serverContainer; var immortalSerializerType = typeOfT.Assembly.GetType($"Ambrosia.ImmortalSerializer"); var immortalSerializer = (ImmortalSerializerBase)Activator.CreateInstance(immortalSerializerType); if (typeof(IEmpty).IsAssignableFrom(typeOfT)) { serverContainer = new EmptyDispatcher(instance, immortalSerializer, serviceName, typeof(T2), typeof(Z2), receivePort, sendPort); } else { var containerClass = typeOfT.Assembly.GetType(typeOfT.FullName + "_Dispatcher_Implementation"); var container = Activator.CreateInstance(containerClass, instance, immortalSerializer, serviceName, typeof(T2), typeof(Z2), receivePort, sendPort); serverContainer = (Immortal.Dispatcher)container; } serverContainer.Start(); return(serverContainer); }
public override void Serialize(Immortal c, Stream writeToStream) { // nned to create var serializer = new DataContractSerializer(c.GetType(), this.KnownTypes.Select(kt => kt.Type).ToArray()); using (var writer = XmlDictionaryWriter.CreateBinaryWriter(writeToStream)) { serializer.WriteObject(writer, c); } }
public override long SerializeSize(Immortal c) { var serializer = new DataContractSerializer(c.GetType(), this.KnownTypes.Select(kt => kt.Type).ToArray()); long retVal = -1; using (var countStream = new CountStream()) { using (var writer = XmlDictionaryWriter.CreateBinaryWriter(countStream)) { serializer.WriteObject(writer, c); } retVal = countStream.Length; } return(retVal); }
/// <summary> /// Gesture that deploys a (non-upgradeable) service. The result is a service that implements the API defined /// in <typeparamref name="T"/>. /// </summary> /// <typeparam name="T">The interface that defines the API of the deployed service.</typeparam> /// <param name="serviceName"></param> /// <param name="instance">The instance to deploy. It must implement <typeparamref name="T"/>.</param> /// <param name="receivePort">The port number on which it listens for messages from Ambrosia.</param> /// <param name="sendPort">The port number which the service uses to send messages to Ambrosia.</param> /// <returns></returns> public static IDisposable Deploy <T>(string serviceName, Immortal instance, int receivePort, int sendPort) { var typeOfT = typeof(T); if (!typeOfT.IsInterface) { throw new ArgumentException($"The type '{typeOfT.Name}' must be an interface."); } var immortalType = instance.GetType(); if (!typeof(IEmpty).IsAssignableFrom(typeOfT) && !immortalType.GetInterfaces().Any(i => i.Equals(typeOfT) || i.IsSubclassOf(typeOfT))) { throw new ArgumentException($"The instance to be deployed is of type '{immortalType.Name}' does not implement the type {typeOfT.Name}."); } // Generate server Ambrosia instance and cache it. Use type parameter T to tell the generation what // interface to generate a proxy for. Immortal.Dispatcher serverContainer; var serializationClass = typeOfT.Assembly.GetTypes().FirstOrDefault(p => p.IsClass && !p.IsAbstract && typeof(ImmortalSerializerBase).IsAssignableFrom(p)); var immortalSerializer = serializationClass == null ? new Immortal.SimpleImmortalSerializer() : (ImmortalSerializerBase)Activator.CreateInstance(serializationClass); if (typeof(IEmpty).IsAssignableFrom(typeOfT)) { serverContainer = new EmptyDispatcher(instance, immortalSerializer, serviceName, receivePort, sendPort); } else { var containerClass = typeOfT.Assembly.GetType(typeOfT.FullName + "_Dispatcher_Implementation"); var container = Activator.CreateInstance(containerClass, instance, immortalSerializer, serviceName, receivePort, sendPort, true); serverContainer = (Immortal.Dispatcher)container; } serverContainer.Start(); return(serverContainer); }