IGNITE-6615 .NET: Thin client: XML configuration
authorPavel Tupitsyn <ptupitsyn@apache.org>
Thu, 21 Dec 2017 10:16:40 +0000 (13:16 +0300)
committerPavel Tupitsyn <ptupitsyn@apache.org>
Thu, 21 Dec 2017 10:16:40 +0000 (13:16 +0300)
This closes #3263

19 files changed:
modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs
modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/IgniteClientConfiguration.xml [new file with mode: 0644]
modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs
modules/platforms/dotnet/Apache.Ignite.Core.Tests/app.config
modules/platforms/dotnet/Apache.Ignite.Core.Tests/custom_app.config
modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.Schema.nuspec
modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs
modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs
modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfigurationSection.cs [new file with mode: 0644]
modules/platforms/dotnet/Apache.Ignite.Core/IgniteClientConfigurationSection.xsd [new file with mode: 0644]
modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.cs
modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs

index 8e4de7f..27c161d 100644 (file)
@@ -89,6 +89,9 @@
     <Content Include="..\Apache.Ignite.Core.Tests\Config\cache-query.xml" Link="Config\cache-query.xml">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="..\Apache.Ignite.Core.Tests\Config\Client\IgniteClientConfiguration.xml" Link="Config\Client\IgniteClientConfiguration.xml">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="..\Apache.Ignite.Core.Tests\Config\Compute\compute-grid1.xml" Link="Config\Compute\compute-grid1.xml">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     <Folder Include="Cache\Query\" />
     <Folder Include="Compute\" />
     <Folder Include="Config\Compute\" />
+    <Folder Include="Config\Client\" />
     <Folder Include="Log\" />
     <Folder Include="DataStructures\" />
     <Folder Include="ThinClient\Cache\" />
   </ItemGroup>
 
   <ItemGroup>
+    <None Include="..\Apache.Ignite.Core.Tests\custom_app.config" Link="custom_app.config">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
     <None Include="Common\TestUtils.DotNetCore.cs" />
   </ItemGroup>
 
index a53b0de..059a6e0 100644 (file)
     <Content Include="Config\Cache\Store\cache-store-session.xml">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="Config\Client\IgniteClientConfiguration.xml">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="Config\Compute\compute-grid1.xml">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
index 6e368a3..145762a 100644 (file)
@@ -94,9 +94,11 @@ namespace Apache.Ignite.Core.Tests.Client
             };
 
             using (Ignition.Start(servCfg))
-            using (Ignition.StartClient(clientCfg))
+            using (var client = Ignition.StartClient(clientCfg))
             {
-                // No-op.
+                Assert.AreNotEqual(clientCfg, client.GetConfiguration());
+                Assert.AreNotEqual(client.GetConfiguration(), client.GetConfiguration());
+                Assert.AreEqual(clientCfg.ToXml(), client.GetConfiguration().ToXml());
             }
         }
 
index 0734f42..0b28cfd 100644 (file)
 
 namespace Apache.Ignite.Core.Tests.Client
 {
+    using System;
+    using System.Configuration;
+    using System.IO;
+    using System.Text;
+    using System.Xml;
+    using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Client;
     using NUnit.Framework;
 
@@ -38,5 +44,163 @@ namespace Apache.Ignite.Core.Tests.Client
             Assert.AreEqual(IgniteClientConfiguration.DefaultSocketBufferSize, cfg.SocketSendBufferSize);
             Assert.AreEqual(IgniteClientConfiguration.DefaultTcpNoDelay, cfg.TcpNoDelay);
         }
+
+        /// <summary>
+        /// Tests the FromXml method.
+        /// </summary>
+        [Test]
+        public void TestFromXml()
+        {
+            // Empty (root element name does not matter).
+            var cfg = IgniteClientConfiguration.FromXml("<foo />");
+            Assert.AreEqual(new IgniteClientConfiguration().ToXml(), cfg.ToXml());
+
+            // Properties.
+            cfg = IgniteClientConfiguration.FromXml("<a host='h' port='123' />");
+            Assert.AreEqual("h", cfg.Host);
+            Assert.AreEqual(123, cfg.Port);
+
+            // Full config.
+            var fullCfg = new IgniteClientConfiguration
+            {
+                Host = "test1",
+                Port = 345,
+                SocketReceiveBufferSize = 222,
+                SocketSendBufferSize = 333,
+                TcpNoDelay = false,
+                BinaryConfiguration = new BinaryConfiguration
+                {
+                    CompactFooter = false,
+                    KeepDeserialized = false,
+                    Types = new[] {"foo", "bar"}
+                }
+            };
+
+            using (var xmlReader = XmlReader.Create(Path.Combine("Config", "Client", "IgniteClientConfiguration.xml")))
+            {
+                xmlReader.MoveToContent();
+
+                cfg = IgniteClientConfiguration.FromXml(xmlReader);
+
+                Assert.AreEqual(cfg.ToXml(), fullCfg.ToXml());
+            }
+        }
+
+        /// <summary>
+        /// Tests the ToXml method.
+        /// </summary>
+        [Test]
+        public void TestToXml()
+        {
+            // Empty config.
+            Assert.AreEqual("<?xml version=\"1.0\" encoding=\"utf-16\"?>" + Environment.NewLine +
+                            "<igniteClientConfiguration " +
+                            "xmlns=\"http://ignite.apache.org/schema/dotnet/IgniteClientConfigurationSection\" />",
+                new IgniteClientConfiguration().ToXml());
+
+            // Some properties.
+            var cfg = new IgniteClientConfiguration
+            {
+                Host = "myHost",
+                Port = 123
+            };
+
+            Assert.AreEqual("<?xml version=\"1.0\" encoding=\"utf-16\"?>" + Environment.NewLine +
+                            "<igniteClientConfiguration host=\"myHost\" port=\"123\" " +
+                            "xmlns=\"http://ignite.apache.org/schema/dotnet/IgniteClientConfigurationSection\" />",
+                cfg.ToXml());
+
+            // Nested objects.
+            cfg = new IgniteClientConfiguration
+            {
+                SocketSendBufferSize = 2,
+                BinaryConfiguration = new BinaryConfiguration {CompactFooter = false}
+            };
+
+            Assert.IsTrue(cfg.ToXml().Contains("<binaryConfiguration compactFooter=\"false\" />"), cfg.ToXml());
+
+            // Custom element name.
+            var sb = new StringBuilder();
+
+            using (var xmlWriter = XmlWriter.Create(sb))
+            {
+                new IgniteClientConfiguration().ToXml(xmlWriter, "fooBar");
+            }
+
+            Assert.AreEqual("<?xml version=\"1.0\" encoding=\"utf-16\"?><fooBar " +
+                            "xmlns=\"http://ignite.apache.org/schema/dotnet/IgniteClientConfigurationSection\" />",
+                sb.ToString());
+        }
+
+        /// <summary>
+        /// Tests client start from application configuration.
+        /// </summary>
+        [Test]
+        public void TestStartFromAppConfig()
+        {
+            using (Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                // Custom file.
+                using (var client = Ignition.StartClient("igniteClientConfiguration", "custom_app.config"))
+                {
+                    Assert.AreEqual(512, client.GetConfiguration().SocketSendBufferSize);
+                }
+
+                // Missing file.
+                var ex = Assert.Throws<ConfigurationErrorsException>(() => Ignition.StartClient("foo", "bar"));
+                Assert.AreEqual("Specified config file does not exist: bar", ex.Message);
+
+#if !NETCOREAPP2_0  // Test runners do not pick up default config.
+                // Default section.
+                using (var client = Ignition.StartClient())
+                {
+                    Assert.AreEqual("127.0.0.1", client.GetConfiguration().Host);
+                    Assert.AreEqual(0, client.GetConfiguration().SocketSendBufferSize);
+                }
+
+                // Custom section.
+                using (var client = Ignition.StartClient("igniteClientConfiguration2"))
+                {
+                    Assert.AreEqual("127.0.0.1", client.GetConfiguration().Host);
+                    Assert.AreEqual(2048, client.GetConfiguration().SocketSendBufferSize);
+                }
+
+                // Missing section content.
+                ex = Assert.Throws<ConfigurationErrorsException>(() => 
+                    Ignition.StartClient("igniteClientConfiguration3"));
+                Assert.AreEqual("IgniteClientConfigurationSection with name 'igniteClientConfiguration3' is " +
+                                "defined in <configSections>, but not present in configuration.", ex.Message);
+
+                // Missing section.
+                ex = Assert.Throws<ConfigurationErrorsException>(() => Ignition.StartClient("foo"));
+                Assert.AreEqual("Could not find IgniteClientConfigurationSection with name 'foo'.", ex.Message);
+#endif
+            }
+        }
+
+#if !NETCOREAPP2_0
+        /// <summary>
+        /// Tests the schema validation.
+        /// </summary>
+        [Test]
+        public void TestSchemaValidation()
+        {
+            var xml = File.ReadAllText("Config\\Client\\IgniteClientConfiguration.xml");
+            var xmlns = "http://ignite.apache.org/schema/dotnet/IgniteClientConfigurationSection";
+            var schemaFile = "IgniteClientConfigurationSection.xsd";
+
+            IgniteConfigurationSerializerTest.CheckSchemaValidation(xml, xmlns, schemaFile);
+        }
+
+        /// <summary>
+        /// Tests that all properties are present in the schema.
+        /// </summary>
+        [Test]
+        public void TestAllPropertiesArePresentInSchema()
+        {
+            IgniteConfigurationSerializerTest.CheckAllPropertiesArePresentInSchema(
+                "IgniteClientConfigurationSection.xsd", "igniteClientConfiguration", typeof(IgniteClientConfiguration));
+        }
+#endif
     }
 }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/IgniteClientConfiguration.xml b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/IgniteClientConfiguration.xml
new file mode 100644 (file)
index 0000000..9a19e32
Binary files /dev/null and b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/IgniteClientConfiguration.xml differ
index 1376d64..7be7acd 100644 (file)
@@ -46,7 +46,6 @@ namespace Apache.Ignite.Core.Tests
     using Apache.Ignite.Core.Discovery.Tcp;
     using Apache.Ignite.Core.Discovery.Tcp.Multicast;
     using Apache.Ignite.Core.Events;
-    using Apache.Ignite.Core.Impl.Common;
     using Apache.Ignite.Core.Lifecycle;
     using Apache.Ignite.Core.Log;
     using Apache.Ignite.Core.PersistentStore;
@@ -356,14 +355,22 @@ namespace Apache.Ignite.Core.Tests
         /// Tests that all properties are present in the schema.
         /// </summary>
         [Test]
-        [SuppressMessage("ReSharper", "PossibleNullReferenceException")]
         public void TestAllPropertiesArePresentInSchema()
         {
-            var schema = XDocument.Load("IgniteConfigurationSection.xsd")
-                    .Root.Elements()
-                    .Single(x => x.Attribute("name").Value == "igniteConfiguration");
+            CheckAllPropertiesArePresentInSchema("IgniteConfigurationSection.xsd", "igniteConfiguration", 
+                typeof(IgniteConfiguration));
+        }
+
+        /// <summary>
+        /// Checks that all properties are present in schema.
+        /// </summary>
+        [SuppressMessage("ReSharper", "PossibleNullReferenceException")]
+        public static void CheckAllPropertiesArePresentInSchema(string xsd, string sectionName, Type type)
+        {
+            var schema = XDocument.Load(xsd)
+                .Root.Elements()
+                .Single(x => x.Attribute("name").Value == sectionName);
 
-            var type = typeof(IgniteConfiguration);
 
             CheckPropertyIsPresentInSchema(type, schema);
         }
@@ -556,29 +563,28 @@ namespace Apache.Ignite.Core.Tests
         /// </summary>
         private static void CheckSchemaValidation()
         {
-            var sb = new StringBuilder();
-
-            using (var xmlWriter = XmlWriter.Create(sb))
-            {
-                IgniteConfigurationXmlSerializer.Serialize(GetTestConfig(), xmlWriter, "igniteConfiguration");
-            }
-
-            CheckSchemaValidation(sb.ToString());
+            CheckSchemaValidation(GetTestConfig().ToXml());
         }
 
         /// <summary>
         /// Checks the schema validation.
         /// </summary>
-        /// <param name="xml">The XML.</param>
         private static void CheckSchemaValidation(string xml)
         {
-            var document = new XmlDocument();
+            var xmlns = "http://ignite.apache.org/schema/dotnet/IgniteConfigurationSection";
+            var schemaFile = "IgniteConfigurationSection.xsd";
 
-            document.Schemas.Add("http://ignite.apache.org/schema/dotnet/IgniteConfigurationSection",
-                XmlReader.Create("IgniteConfigurationSection.xsd"));
+            CheckSchemaValidation(xml, xmlns, schemaFile);
+        }
 
+        /// <summary>
+        /// Checks the schema validation.
+        /// </summary>
+        public static void CheckSchemaValidation(string xml, string xmlns, string schemaFile)
+        {
+            var document = new XmlDocument();
+            document.Schemas.Add(xmlns, XmlReader.Create(schemaFile));
             document.Load(new StringReader(xml));
-
             document.Validate(null);
         }
 
index be08e61..8456806 100644 (file)
         <section name="igniteConfiguration" type="Apache.Ignite.Core.IgniteConfigurationSection, Apache.Ignite.Core" />
         <section name="igniteConfiguration2" type="Apache.Ignite.Core.IgniteConfigurationSection, Apache.Ignite.Core" />
         <section name="igniteConfigurationMissing" type="Apache.Ignite.Core.IgniteConfigurationSection, Apache.Ignite.Core" />
+
+        <section name="igniteClientConfiguration" type="Apache.Ignite.Core.Client.IgniteClientConfigurationSection, Apache.Ignite.Core" />
+        <section name="igniteClientConfiguration2" type="Apache.Ignite.Core.Client.IgniteClientConfigurationSection, Apache.Ignite.Core" />
+        <section name="igniteClientConfiguration3" type="Apache.Ignite.Core.Client.IgniteClientConfigurationSection, Apache.Ignite.Core" />
     </configSections>
 
     <runtime>
@@ -36,7 +40,7 @@
                 </endpoints>
             </ipFinder>
         </discoverySpi>
-        
+
         <cacheConfiguration>
             <cacheConfiguration name="cacheName" />
         </cacheConfiguration>
@@ -56,4 +60,6 @@
         </cacheConfiguration>
     </igniteConfiguration2>
 
+    <igniteClientConfiguration host="127.0.0.1" />
+    <igniteClientConfiguration2 host="127.0.0.1" socketSendBufferSize="2048" />
 </configuration>
index cb3af7c..b79279a 100644 (file)
@@ -21,6 +21,9 @@
     <configSections>
         <section name="igniteConfiguration3" type="Apache.Ignite.Core.IgniteConfigurationSection, Apache.Ignite.Core" />
         <section name="igniteConfigurationMissing" type="Apache.Ignite.Core.IgniteConfigurationSection, Apache.Ignite.Core" />
+
+        <section name="igniteClientConfiguration" type="Apache.Ignite.Core.Client.IgniteClientConfigurationSection, Apache.Ignite.Core" />
+        <section name="igniteClientConfiguration2" type="Apache.Ignite.Core.Client.IgniteClientConfigurationSection, Apache.Ignite.Core" />
     </configSections>
 
     <igniteConfiguration3 igniteInstanceName="myGrid3" localhost="127.0.0.1">
@@ -32,4 +35,6 @@
             </ipFinder>
         </discoverySpi>
     </igniteConfiguration3>
+
+    <igniteClientConfiguration host="127.0.0.1" socketSendBufferSize="512" />
 </configuration>
index 52dc1e0..ca8efe3 100644 (file)
@@ -48,5 +48,6 @@ More info on Apache Ignite.NET: https://apacheignite-net.readme.io/
     <files>
         <!-- Other files should go to Content folder to be automatically included in project. -->
         <file src="IgniteConfigurationSection.xsd" target="content" />
+        <file src="IgniteClientConfigurationSection.xsd" target="content" />
     </files>
 </package>
\ No newline at end of file
index 2852853..cdde538 100644 (file)
@@ -97,6 +97,7 @@
     <Compile Include="Cache\Configuration\CacheKeyConfiguration.cs" />
     <Compile Include="Cache\Configuration\DataPageEvictionMode.cs" />
     <Compile Include="Client\Cache\CacheClientConfiguration.cs" />
+    <Compile Include="Client\IgniteClientConfigurationSection.cs" />
     <Compile Include="Configuration\CheckpointWriteOrder.cs" />
     <Compile Include="Configuration\DataPageEvictionMode.cs" />
     <Compile Include="Configuration\DataRegionConfiguration.cs" />
     <None Include="Apache.Ignite.Core.ruleset" />
     <None Include="Apache.Ignite.Core.nuspec" />
     <None Include="Apache.Ignite.Core.Schema.nuspec" />
+    <None Include="IgniteClientConfigurationSection.xsd">
+      <SubType>Designer</SubType>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
     <None Include="NuGet\Uninstall.ps1" />
     <None Include="NuGet\PostBuild.ps1" />
     <None Include="NuGet\Install.ps1" />
index 9bca883..58f12fe 100644 (file)
@@ -25,7 +25,8 @@ namespace Apache.Ignite.Core.Client
 
     /// <summary>
     /// Main entry point for Ignite Thin Client APIs.
-    /// You can obtain an instance of <see cref="IIgniteClient"/> through <see cref="Ignition.StartClient"/>.
+    /// You can obtain an instance of <see cref="IIgniteClient"/> through one of the
+    /// <see cref="Ignition.StartClient()"/> overloads.
     /// </summary>
     public interface IIgniteClient : IDisposable
     {
@@ -99,5 +100,11 @@ namespace Apache.Ignite.Core.Client
         /// <returns>Instance of <see cref="IBinary"/> interface</returns>
         [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Semantics.")]
         IBinary GetBinary();
+
+        /// <summary>
+        /// Gets the configuration.
+        /// </summary>
+        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Semantics.")]
+        IgniteClientConfiguration GetConfiguration();
     }
 }
index 8c9b6a1..e46ede4 100644 (file)
 namespace Apache.Ignite.Core.Client
 {
     using System.ComponentModel;
+    using System.Xml;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Common;
 
     /// <summary>
     /// Ignite thin client configuration.
@@ -57,6 +59,31 @@ namespace Apache.Ignite.Core.Client
         }
 
         /// <summary>
+        /// Initializes a new instance of the <see cref="IgniteClientConfiguration"/> class.
+        /// </summary>
+        /// <param name="cfg">The configuration to copy.</param>
+        public IgniteClientConfiguration(IgniteClientConfiguration cfg) : this()
+        {
+            if (cfg == null)
+            {
+                return;
+            }
+
+            Host = cfg.Host;
+            Port = cfg.Port;
+            SocketSendBufferSize = cfg.SocketSendBufferSize;
+            SocketReceiveBufferSize = cfg.SocketReceiveBufferSize;
+            TcpNoDelay = cfg.TcpNoDelay;
+
+            if (cfg.BinaryConfiguration != null)
+            {
+                BinaryConfiguration = new BinaryConfiguration(cfg.BinaryConfiguration);
+            }
+
+            BinaryProcessor = cfg.BinaryProcessor;
+        }
+
+        /// <summary>
         /// Gets or sets the host. Should not be null.
         /// </summary>
         public string Host { get; set; }
@@ -100,5 +127,43 @@ namespace Apache.Ignite.Core.Client
         /// Gets or sets custom binary processor. Internal property for tests.
         /// </summary>
         internal IBinaryProcessor BinaryProcessor { get; set; }
+
+        /// <summary>
+        /// Serializes this instance to the specified XML writer.
+        /// </summary>
+        /// <param name="writer">The writer.</param>
+        /// <param name="rootElementName">Name of the root element.</param>
+        public void ToXml(XmlWriter writer, string rootElementName)
+        {
+            IgniteConfigurationXmlSerializer.Serialize(this, writer, rootElementName);
+        }
+
+        /// <summary>
+        /// Serializes this instance to an XML string.
+        /// </summary>
+        public string ToXml()
+        {
+            return IgniteConfigurationXmlSerializer.Serialize(this, "igniteClientConfiguration");
+        }
+
+        /// <summary>
+        /// Deserializes IgniteClientConfiguration from the XML reader.
+        /// </summary>
+        /// <param name="reader">The reader.</param>
+        /// <returns>Deserialized instance.</returns>
+        public static IgniteClientConfiguration FromXml(XmlReader reader)
+        {
+            return IgniteConfigurationXmlSerializer.Deserialize<IgniteClientConfiguration>(reader);
+        }
+
+        /// <summary>
+        /// Deserializes IgniteClientConfiguration from the XML string.
+        /// </summary>
+        /// <param name="xml">Xml string.</param>
+        /// <returns>Deserialized instance.</returns>
+        public static IgniteClientConfiguration FromXml(string xml)
+        {
+            return IgniteConfigurationXmlSerializer.Deserialize<IgniteClientConfiguration>(xml);
+        }
     }
 }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfigurationSection.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfigurationSection.cs
new file mode 100644 (file)
index 0000000..8f572c6
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Client
+{
+    using System.Configuration;
+    using System.Text;
+    using System.Xml;
+    using Apache.Ignite.Core.Impl.Common;
+
+    /// <summary>
+    /// Ignite configuration section for app.config and web.config files.
+    /// </summary>
+    public class IgniteClientConfigurationSection : ConfigurationSection
+    {
+        /// <summary>
+        /// Gets the Ignite client configuration.
+        /// </summary>
+        public IgniteClientConfiguration IgniteClientConfiguration { get; private set; }
+
+        /// <summary>
+        /// Reads XML from the configuration file.
+        /// </summary>
+        /// <param name="reader">The reader object, which reads from the configuration file.</param>
+        protected override void DeserializeSection(XmlReader reader)
+        {
+            IgniteArgumentCheck.NotNull(reader, "reader");
+
+            IgniteClientConfiguration = IgniteConfigurationXmlSerializer
+                .Deserialize<IgniteClientConfiguration>(reader);
+        }
+
+        /// <summary>
+        /// Creates an XML string containing an unmerged view of the <see cref="ConfigurationSection" /> 
+        /// object as a single section to write to a file.
+        /// </summary>
+        /// <param name="parentElement">The <see cref="ConfigurationElement" /> 
+        /// instance to use as the parent when performing the un-merge.</param>
+        /// <param name="name">The name of the section to create.</param>
+        /// <param name="saveMode">The <see cref="ConfigurationSaveMode" /> instance 
+        /// to use when writing to a string.</param>
+        /// <returns>
+        /// An XML string containing an unmerged view of the <see cref="ConfigurationSection" /> object.
+        /// </returns>
+        protected override string SerializeSection(ConfigurationElement parentElement, string name, 
+            ConfigurationSaveMode saveMode)
+        {
+            IgniteArgumentCheck.NotNull(parentElement, "parentElement");
+            IgniteArgumentCheck.NotNullOrEmpty(name, "name");
+
+            if (IgniteClientConfiguration == null)
+            {
+                return string.Format("<{0} />", name);
+            }
+
+            var sb = new StringBuilder();
+
+            using (var xmlWriter = XmlWriter.Create(sb))
+            {
+                IgniteConfigurationXmlSerializer.Serialize(IgniteClientConfiguration, xmlWriter, name);
+
+                return sb.ToString();
+            }
+        }
+    }
+}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteClientConfigurationSection.xsd b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteClientConfigurationSection.xsd
new file mode 100644 (file)
index 0000000..e7a6889
--- /dev/null
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<xs:schema id="IgniteClientConfigurationSection"
+    targetNamespace="http://ignite.apache.org/schema/dotnet/IgniteClientConfigurationSection"
+    elementFormDefault="qualified"
+    xmlns="http://ignite.apache.org/schema/dotnet/IgniteClientConfigurationSection"
+    xmlns:mstns="http://ignite.apache.org/schema/dotnet/IgniteClientConfigurationSection"
+    xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+    <xs:element name="igniteClientConfiguration">
+        <xs:annotation>
+            <xs:documentation>Ignite thin client configuration root.</xs:documentation>
+        </xs:annotation>
+        <xs:complexType>
+            <xs:all>
+                <xs:element name="binaryConfiguration" minOccurs="0">
+                    <xs:annotation>
+                        <xs:documentation>Binary configuration.</xs:documentation>
+                    </xs:annotation>
+                    <xs:complexType>
+                        <xs:all>
+                            <xs:element name="typeConfigurations" minOccurs="0">
+                                <xs:annotation>
+                                    <xs:documentation>Type configurations.</xs:documentation>
+                                </xs:annotation>
+                                <xs:complexType>
+                                    <xs:sequence>
+                                        <xs:element name="binaryTypeConfiguration" maxOccurs="unbounded">
+                                            <xs:complexType>
+                                                <xs:all>
+                                                    <xs:element name="nameMapper" minOccurs="0">
+                                                        <xs:annotation>
+                                                            <xs:documentation>Name mapper for the given type.</xs:documentation>
+                                                        </xs:annotation>
+                                                        <xs:complexType>
+                                                            <xs:attribute name="type" type="xs:string" use="required">
+                                                                <xs:annotation>
+                                                                    <xs:documentation>Assembly-qualified type name.</xs:documentation>
+                                                                </xs:annotation>
+                                                            </xs:attribute>
+                                                        </xs:complexType>
+                                                    </xs:element>
+                                                    <xs:element name="idMapper" minOccurs="0">
+                                                        <xs:annotation>
+                                                            <xs:documentation>ID mapper for the given type. When it is necessary to resolve class (field) ID, then this property will be checked first. Otherwise, ID will be hash code of the class (field) simple name in lower case.</xs:documentation>
+                                                        </xs:annotation>
+                                                        <xs:complexType>
+                                                            <xs:attribute name="type" type="xs:string" use="required">
+                                                                <xs:annotation>
+                                                                    <xs:documentation>Assembly-qualified type name.</xs:documentation>
+                                                                </xs:annotation>
+                                                            </xs:attribute>
+                                                        </xs:complexType>
+                                                    </xs:element>
+                                                    <xs:element name="serializer" minOccurs="0">
+                                                        <xs:annotation>
+                                                            <xs:documentation>
+                                                                Serializer for the given type. If not provided and class implements IBinarizable then its custom logic will be used. If not provided and class doesn't implement IBinarizable then all fields of the class except of those with [NotSerialized] attribute will be serialized with help of reflection.
+                                                            </xs:documentation>
+                                                        </xs:annotation>
+                                                        <xs:complexType>
+                                                            <xs:attribute name="type" type="xs:string" use="required">
+                                                                <xs:annotation>
+                                                                    <xs:documentation>Assembly-qualified type name.</xs:documentation>
+                                                                </xs:annotation>
+                                                            </xs:attribute>
+                                                        </xs:complexType>
+                                                    </xs:element>
+                                                </xs:all>
+                                                <xs:attribute name="typeName" type="xs:string">
+                                                    <xs:annotation>
+                                                        <xs:documentation>Fully qualified type name.</xs:documentation>
+                                                    </xs:annotation>
+                                                </xs:attribute>
+                                                <xs:attribute name="affinityKeyFieldName" type="xs:string">
+                                                    <xs:annotation>
+                                                        <xs:documentation>Affinity key field name.</xs:documentation>
+                                                    </xs:annotation>
+                                                </xs:attribute>
+                                                <xs:attribute name="keepDeserialized" type="xs:string">
+                                                    <xs:annotation>
+                                                        <xs:documentation>
+                                                            Keep deserialized flag. If set to non-null value, overrides default value set in BinaryTypeConfiguration.
+                                                        </xs:documentation>
+                                                    </xs:annotation>
+                                                </xs:attribute>
+                                                <xs:attribute name="isEnum" type="xs:boolean">
+                                                    <xs:annotation>
+                                                        <xs:documentation>Whether this instance describes an enum type.</xs:documentation>
+                                                    </xs:annotation>
+                                                </xs:attribute>
+                                            </xs:complexType>
+                                        </xs:element>
+                                    </xs:sequence>
+                                </xs:complexType>
+                            </xs:element>
+                            <xs:element name="types" minOccurs="0">
+                                <xs:annotation>
+                                    <xs:documentation>
+                                        Assembly-qualified type names (Type.AssemblyQualifiedName) for binarizable types. Shorthand for creating BinaryTypeConfiguration.
+                                    </xs:documentation>
+                                </xs:annotation>
+                                <xs:complexType>
+                                    <xs:sequence>
+                                        <xs:element maxOccurs="unbounded" name="string" type="xs:string" />
+                                    </xs:sequence>
+                                </xs:complexType>
+                            </xs:element>
+                            <xs:element name="nameMapper" minOccurs="0">
+                                <xs:annotation>
+                                    <xs:documentation>Default name mapper.</xs:documentation>
+                                </xs:annotation>
+                                <xs:complexType>
+                                    <xs:attribute name="type" type="xs:string" use="required">
+                                        <xs:annotation>
+                                            <xs:documentation>Assembly-qualified type name.</xs:documentation>
+                                        </xs:annotation>
+                                    </xs:attribute>
+                                </xs:complexType>
+                            </xs:element>
+                            <xs:element name="idMapper" minOccurs="0">
+                                <xs:annotation>
+                                    <xs:documentation>Default ID mapper.</xs:documentation>
+                                </xs:annotation>
+                                <xs:complexType>
+                                    <xs:attribute name="type" type="xs:string" use="required">
+                                        <xs:annotation>
+                                            <xs:documentation>Assembly-qualified type name.</xs:documentation>
+                                        </xs:annotation>
+                                    </xs:attribute>
+                                </xs:complexType>
+                            </xs:element>
+                            <xs:element name="serializer" minOccurs="0">
+                                <xs:annotation>
+                                    <xs:documentation>Default serializer.</xs:documentation>
+                                </xs:annotation>
+                                <xs:complexType>
+                                    <xs:attribute name="type" type="xs:string" use="required">
+                                        <xs:annotation>
+                                            <xs:documentation>Assembly-qualified type name.</xs:documentation>
+                                        </xs:annotation>
+                                    </xs:attribute>
+                                </xs:complexType>
+                            </xs:element>
+                        </xs:all>
+                        <xs:attribute name="keepDeserialized" type="xs:boolean">
+                            <xs:annotation>
+                                <xs:documentation>Default keep deserialized flag.</xs:documentation>
+                            </xs:annotation>
+                        </xs:attribute>
+                        <xs:attribute name="compactFooter" type="xs:boolean">
+                            <xs:annotation>
+                                <xs:documentation>Compact footer flag.</xs:documentation>
+                            </xs:annotation>
+                        </xs:attribute>
+                    </xs:complexType>
+                </xs:element>
+            </xs:all>
+            <xs:attribute name="host" type="xs:string" use="required">
+                <xs:annotation>
+                    <xs:documentation>Host to connect to, required property.</xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="port" type="xs:int">
+                <xs:annotation>
+                    <xs:documentation>Target port.</xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="socketSendBufferSize" type="xs:int">
+                <xs:annotation>
+                    <xs:documentation>Size of the socket send buffer. When set to 0, operating system default is used.</xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="socketReceiveBufferSize" type="xs:int">
+                <xs:annotation>
+                    <xs:documentation>Size of the socket receive buffer. When set to 0, operating system default is used.</xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="tcpNoDelay" type="xs:boolean">
+                <xs:annotation>
+                    <xs:documentation>Value for TCP_NODELAY socket option.</xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+        </xs:complexType>
+    </xs:element>
+</xs:schema>
\ No newline at end of file
index 8c39091..f63d959 100644 (file)
@@ -24,7 +24,6 @@ namespace Apache.Ignite.Core
     using System.Diagnostics.CodeAnalysis;
     using System.IO;
     using System.Linq;
-    using System.Text;
     using System.Xml;
     using System.Xml.Serialization;
     using Apache.Ignite.Core.Binary;
@@ -1153,9 +1152,6 @@ namespace Apache.Ignite.Core
         /// <param name="rootElementName">Name of the root element.</param>
         public void ToXml(XmlWriter writer, string rootElementName)
         {
-            IgniteArgumentCheck.NotNull(writer, "writer");
-            IgniteArgumentCheck.NotNullOrEmpty(rootElementName, "rootElementName");
-
             IgniteConfigurationXmlSerializer.Serialize(this, writer, rootElementName);
         }
 
@@ -1164,19 +1160,7 @@ namespace Apache.Ignite.Core
         /// </summary>
         public string ToXml()
         {
-            var sb = new StringBuilder();
-
-            var settings = new XmlWriterSettings
-            {
-                Indent = true
-            };
-
-            using (var xmlWriter = XmlWriter.Create(sb, settings))
-            {
-                ToXml(xmlWriter, "igniteConfiguration");
-            }
-
-            return sb.ToString();
+            return IgniteConfigurationXmlSerializer.Serialize(this, "igniteConfiguration");
         }
 
         /// <summary>
@@ -1186,9 +1170,7 @@ namespace Apache.Ignite.Core
         /// <returns>Deserialized instance.</returns>
         public static IgniteConfiguration FromXml(XmlReader reader)
         {
-            IgniteArgumentCheck.NotNull(reader, "reader");
-
-            return IgniteConfigurationXmlSerializer.Deserialize(reader);
+            return IgniteConfigurationXmlSerializer.Deserialize<IgniteConfiguration>(reader);
         }
 
         /// <summary>
@@ -1196,20 +1178,9 @@ namespace Apache.Ignite.Core
         /// </summary>
         /// <param name="xml">Xml string.</param>
         /// <returns>Deserialized instance.</returns>
-        [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
-        [SuppressMessage("Microsoft.Usage", "CA2202: Do not call Dispose more than one time on an object")]
         public static IgniteConfiguration FromXml(string xml)
         {
-            IgniteArgumentCheck.NotNullOrEmpty(xml, "xml");
-
-            using (var stringReader = new StringReader(xml))
-            using (var xmlReader = XmlReader.Create(stringReader))
-            {
-                // Skip XML header.
-                xmlReader.MoveToContent();
-
-                return FromXml(xmlReader);
-            }
+            return IgniteConfigurationXmlSerializer.Deserialize<IgniteConfiguration>(xml);
         }
 
         /// <summary>
index 51b963e..4cecb65 100644 (file)
@@ -43,7 +43,7 @@ namespace Apache.Ignite.Core
         {
             IgniteArgumentCheck.NotNull(reader, "reader");
 
-            IgniteConfiguration = IgniteConfigurationXmlSerializer.Deserialize(reader);
+            IgniteConfiguration = IgniteConfigurationXmlSerializer.Deserialize<IgniteConfiguration>(reader);
         }
 
         /// <summary>
index 46b9ec5..20d6dc3 100644 (file)
@@ -61,6 +61,11 @@ namespace Apache.Ignite.Core
         /// </summary>
         public const string ConfigurationSectionName = "igniteConfiguration";
 
+        /// <summary>
+        /// Default configuration section name.
+        /// </summary>
+        public const string ClientConfigurationSectionName = "igniteClientConfiguration";
+
         /** */
         private static readonly object SyncRoot = new object();
 
@@ -171,26 +176,41 @@ namespace Apache.Ignite.Core
         /// <returns>Started Ignite.</returns>
         public static IIgnite StartFromApplicationConfiguration(string sectionName, string configPath)
         {
+            var section = GetConfigurationSection<IgniteConfigurationSection>(sectionName, configPath);
+
+            if (section.IgniteConfiguration == null)
+            {
+                throw new ConfigurationErrorsException(
+                    string.Format("{0} with name '{1}' in file '{2}' is defined in <configSections>, " +
+                                  "but not present in configuration.",
+                        typeof(IgniteConfigurationSection).Name, sectionName, configPath));
+            }
+
+            return Start(section.IgniteConfiguration);
+        }
+
+        /// <summary>
+        /// Gets the configuration section.
+        /// </summary>
+        private static T GetConfigurationSection<T>(string sectionName, string configPath)
+            where T : ConfigurationSection
+        {
             IgniteArgumentCheck.NotNullOrEmpty(sectionName, "sectionName");
             IgniteArgumentCheck.NotNullOrEmpty(configPath, "configPath");
 
             var fileMap = GetConfigMap(configPath);
             var config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
 
-            var section = config.GetSection(sectionName) as IgniteConfigurationSection;
+            var section = config.GetSection(sectionName) as T;
 
             if (section == null)
+            {
                 throw new ConfigurationErrorsException(
                     string.Format("Could not find {0} with name '{1}' in file '{2}'",
-                        typeof(IgniteConfigurationSection).Name, sectionName, configPath));
-
-            if (section.IgniteConfiguration == null)
-                throw new ConfigurationErrorsException(
-                    string.Format("{0} with name '{1}' in file '{2}' is defined in <configSections>, " +
-                                  "but not present in configuration.",
-                        typeof(IgniteConfigurationSection).Name, sectionName, configPath));
+                        typeof(T).Name, sectionName, configPath));
+            }
 
-            return Start(section.IgniteConfiguration);
+            return section;
         }
 
         /// <summary>
@@ -749,7 +769,7 @@ namespace Apache.Ignite.Core
         /// Thin client connects to an existing Ignite node with a socket and does not start JVM in process.
         /// </summary>
         /// <param name="clientConfiguration">The client configuration.</param>
-        /// <returns>Ignite instance.</returns>
+        /// <returns>Ignite client instance.</returns>
         public static IIgniteClient StartClient(IgniteClientConfiguration clientConfiguration)
         {
             IgniteArgumentCheck.NotNull(clientConfiguration, "clientConfiguration");
@@ -759,6 +779,74 @@ namespace Apache.Ignite.Core
         }
 
         /// <summary>
+        /// Reads <see cref="IgniteClientConfiguration"/> from application configuration
+        /// <see cref="IgniteClientConfigurationSection"/> with <see cref="ClientConfigurationSectionName"/>
+        /// name and connects Ignite lightweight (thin) client to an Ignite node.
+        /// <para />
+        /// Thin client connects to an existing Ignite node with a socket and does not start JVM in process.
+        /// </summary>
+        /// <returns>Ignite client instance.</returns>
+        public static IIgniteClient StartClient()
+        {
+            // ReSharper disable once IntroduceOptionalParameters.Global
+            return StartClient(ClientConfigurationSectionName);
+        }
+
+        /// <summary>
+        /// Reads <see cref="IgniteClientConfiguration" /> from application configuration
+        /// <see cref="IgniteClientConfigurationSection" /> with specified name and connects
+        /// Ignite lightweight (thin) client to an Ignite node.
+        /// <para />
+        /// Thin client connects to an existing Ignite node with a socket and does not start JVM in process.
+        /// </summary>
+        /// <param name="sectionName">Name of the configuration section.</param>
+        /// <returns>Ignite client instance.</returns>
+        public static IIgniteClient StartClient(string sectionName)
+        {
+            IgniteArgumentCheck.NotNullOrEmpty(sectionName, "sectionName");
+
+            var section = ConfigurationManager.GetSection(sectionName) as IgniteClientConfigurationSection;
+
+            if (section == null)
+            {
+                throw new ConfigurationErrorsException(string.Format("Could not find {0} with name '{1}'.",
+                    typeof(IgniteClientConfigurationSection).Name, sectionName));
+            }
+
+            if (section.IgniteClientConfiguration == null)
+            {
+                throw new ConfigurationErrorsException(
+                    string.Format("{0} with name '{1}' is defined in <configSections>, " +
+                                  "but not present in configuration.",
+                        typeof(IgniteClientConfigurationSection).Name, sectionName));
+            }
+
+            return StartClient(section.IgniteClientConfiguration);
+        }
+
+        /// <summary>
+        /// Reads <see cref="IgniteConfiguration" /> from application configuration
+        /// <see cref="IgniteConfigurationSection" /> with specified name and starts Ignite.
+        /// </summary>
+        /// <param name="sectionName">Name of the section.</param>
+        /// <param name="configPath">Path to the configuration file.</param>
+        /// <returns>Started Ignite.</returns>
+        public static IIgniteClient StartClient(string sectionName, string configPath)
+        {
+            var section = GetConfigurationSection<IgniteClientConfigurationSection>(sectionName, configPath);
+
+            if (section.IgniteClientConfiguration == null)
+            {
+                throw new ConfigurationErrorsException(
+                    string.Format("{0} with name '{1}' in file '{2}' is defined in <configSections>, " +
+                                  "but not present in configuration.",
+                        typeof(IgniteClientConfigurationSection).Name, sectionName, configPath));
+            }
+
+            return StartClient(section.IgniteClientConfiguration);
+        }
+
+        /// <summary>
         /// Handles the DomainUnload event of the CurrentDomain control.
         /// </summary>
         /// <param name="sender">The source of the event.</param>
index 10bf38f..1b1aa6f 100644 (file)
@@ -34,7 +34,7 @@ namespace Apache.Ignite.Core.Impl.Client
     using Apache.Ignite.Core.Impl.Plugin;
 
     /// <summary>
-    /// Thin client implementation
+    /// Thin client implementation.
     /// </summary>
     internal class IgniteClient : IIgniteInternal, IIgniteClient
     {
@@ -50,6 +50,9 @@ namespace Apache.Ignite.Core.Impl.Client
         /** Binary. */
         private readonly IBinary _binary;
 
+        /** Configuration. */
+        private readonly IgniteClientConfiguration _configuration;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="IgniteClient"/> class.
         /// </summary>
@@ -58,14 +61,16 @@ namespace Apache.Ignite.Core.Impl.Client
         {
             Debug.Assert(clientConfiguration != null);
 
-            _socket = new ClientSocket(clientConfiguration);
+            _configuration = new IgniteClientConfiguration(clientConfiguration);
+
+            _socket = new ClientSocket(_configuration);
 
-            _marsh = new Marshaller(clientConfiguration.BinaryConfiguration)
+            _marsh = new Marshaller(_configuration.BinaryConfiguration)
             {
                 Ignite = this
             };
 
-            _binProc = clientConfiguration.BinaryProcessor ?? new BinaryProcessorClient(_socket);
+            _binProc = _configuration.BinaryProcessor ?? new BinaryProcessorClient(_socket);
 
             _binary = new Binary(_marsh);
         }
@@ -163,6 +168,13 @@ namespace Apache.Ignite.Core.Impl.Client
         }
 
         /** <inheritDoc /> */
+        public IgniteClientConfiguration GetConfiguration()
+        {
+            // Return a copy to allow modifications by the user.
+            return new IgniteClientConfiguration(_configuration);
+        }
+
+        /** <inheritDoc /> */
         public IBinaryProcessor BinaryProcessor
         {
             get { return _binProc; }
index 9a65a24..9f422f1 100644 (file)
@@ -23,8 +23,11 @@ namespace Apache.Ignite.Core.Impl.Common
     using System.ComponentModel;
     using System.Configuration;
     using System.Diagnostics;
+    using System.Diagnostics.CodeAnalysis;
+    using System.IO;
     using System.Linq;
     using System.Reflection;
+    using System.Text;
     using System.Xml;
     using System.Xml.Serialization;
     using Apache.Ignite.Core.Events;
@@ -32,7 +35,7 @@ namespace Apache.Ignite.Core.Impl.Common
     using Apache.Ignite.Core.Impl.Events;
 
     /// <summary>
-    /// Serializes <see cref="IgniteConfiguration"/> to XML.
+    /// Serializes and deserializes Ignite configurations to and from XML.
     /// </summary>
     internal static class IgniteConfigurationXmlSerializer
     {
@@ -46,18 +49,39 @@ namespace Apache.Ignite.Core.Impl.Common
         private const string KeyValPairElement = "pair";
 
         /** Schema. */
-        private const string Schema = "http://ignite.apache.org/schema/dotnet/IgniteConfigurationSection";
+        private const string Schema = "http://ignite.apache.org/schema/dotnet/{0}Section";
 
         /// <summary>
-        /// Deserializes <see cref="IgniteConfiguration"/> from specified <see cref="XmlReader"/>.
+        /// Deserializes configuration of specified type from XML string.
+        /// </summary>
+        /// <param name="xml">Xml string.</param>
+        /// <returns>Resulting configuration.</returns>
+        [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
+        [SuppressMessage("Microsoft.Usage", "CA2202: Do not call Dispose more than one time on an object")]
+        public static T Deserialize<T>(string xml) where T : new()
+        {
+            IgniteArgumentCheck.NotNullOrEmpty(xml, "xml");
+
+            using (var stringReader = new StringReader(xml))
+            using (var xmlReader = XmlReader.Create(stringReader))
+            {
+                // Skip XML header.
+                xmlReader.MoveToContent();
+
+                return Deserialize<T>(xmlReader);
+            }
+        }
+
+        /// <summary>
+        /// Deserializes configuration of specified type from specified <see cref="XmlReader"/>.
         /// </summary>
         /// <param name="reader">The reader.</param>
-        /// <returns>Resulting <see cref="IgniteConfiguration"/>.</returns>
-        public static IgniteConfiguration Deserialize(XmlReader reader)
+        /// <returns>Resulting configuration.</returns>
+        public static T Deserialize<T>(XmlReader reader) where T : new()
         {
             IgniteArgumentCheck.NotNull(reader, "reader");
 
-            var cfg = new IgniteConfiguration();
+            var cfg = new T();
 
             if (reader.NodeType == XmlNodeType.Element || reader.Read())
                 ReadElement(reader, cfg, new TypeResolver());
@@ -66,25 +90,48 @@ namespace Apache.Ignite.Core.Impl.Common
         }
 
         /// <summary>
-        /// Serializes specified <see cref="IgniteConfiguration" /> to <see cref="XmlWriter" />.
+        /// Serializes specified configuration to <see cref="XmlWriter" />.
         /// </summary>
         /// <param name="configuration">The configuration.</param>
         /// <param name="writer">The writer.</param>
         /// <param name="rootElementName">Name of the root element.</param>
-        public static void Serialize(IgniteConfiguration configuration, XmlWriter writer, string rootElementName)
+        public static void Serialize(object configuration, XmlWriter writer, string rootElementName)
         {
             IgniteArgumentCheck.NotNull(configuration, "configuration");
             IgniteArgumentCheck.NotNull(writer, "writer");
             IgniteArgumentCheck.NotNullOrEmpty(rootElementName, "rootElementName");
 
-            WriteElement(configuration, writer, rootElementName, typeof(IgniteConfiguration));
+            WriteElement(configuration, writer, rootElementName, configuration.GetType(), writeSchema: true);
+        }
+
+        /// <summary>
+        /// Serializes specified configuration to <see cref="XmlWriter" />.
+        /// </summary>
+        /// <param name="configuration">The configuration.</param>
+        /// <param name="rootElementName">Name of the root element.</param>
+        /// <returns>XML string.</returns>
+        public static string Serialize(object configuration, string rootElementName)
+        {
+            var sb = new StringBuilder();
+
+            var settings = new XmlWriterSettings
+            {
+                Indent = true
+            };
+
+            using (var xmlWriter = XmlWriter.Create(sb, settings))
+            {
+                Serialize(configuration, xmlWriter, rootElementName);
+            }
+
+            return sb.ToString();
         }
 
         /// <summary>
         /// Writes new element.
         /// </summary>
         private static void WriteElement(object obj, XmlWriter writer, string rootElementName, Type valueType, 
-            PropertyInfo property = null)
+            PropertyInfo property = null, bool writeSchema = false)
         {
             if (property != null)
             {
@@ -95,10 +142,15 @@ namespace Apache.Ignite.Core.Impl.Common
                     return;
             }
 
-            if (valueType == typeof(IgniteConfiguration))
-                writer.WriteStartElement(rootElementName, Schema);  // write xmlns for the root element
+            if (writeSchema)
+            {
+                // Write xmlns for the root element.
+                writer.WriteStartElement(rootElementName, string.Format(Schema, valueType.Name));
+            }
             else
+            {
                 writer.WriteStartElement(rootElementName);
+            }
 
             if (IsBasicType(valueType))
                 WriteBasicProperty(obj, writer, valueType, property);