Return-Path: X-Original-To: apmail-ignite-commits-archive@minotaur.apache.org Delivered-To: apmail-ignite-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 5C662187F3 for ; Tue, 9 Feb 2016 11:54:25 +0000 (UTC) Received: (qmail 40898 invoked by uid 500); 9 Feb 2016 11:54:25 -0000 Delivered-To: apmail-ignite-commits-archive@ignite.apache.org Received: (qmail 40817 invoked by uid 500); 9 Feb 2016 11:54:25 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 40806 invoked by uid 99); 9 Feb 2016 11:54:24 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 09 Feb 2016 11:54:24 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 4E9DEDFA3D; Tue, 9 Feb 2016 11:54:24 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: vozerov@apache.org To: commits@ignite.apache.org Date: Tue, 09 Feb 2016 11:54:25 -0000 Message-Id: In-Reply-To: <6561750708ca472babe1e537f806cb0c@git.apache.org> References: <6561750708ca472babe1e537f806cb0c@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [2/2] ignite git commit: IGNITE-2380: Added ability to start Ignite using configuration from app.config. This closes #417. IGNITE-2380: Added ability to start Ignite using configuration from app.config. This closes #417. Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/a4d8a049 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/a4d8a049 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/a4d8a049 Branch: refs/heads/master Commit: a4d8a049138a4d4bc86a59ccb273f7e214baf694 Parents: f7c1296 Author: Pavel Tupitsyn Authored: Tue Feb 9 14:54:20 2016 +0300 Committer: vozerov-gridgain Committed: Tue Feb 9 14:54:20 2016 +0300 ---------------------------------------------------------------------- .../Apache.Ignite.Core.Tests.csproj | 4 + .../Apache.Ignite.Core.Tests/FutureTest.cs | 1 + .../IgniteConfigurationSectionTest.cs | 69 +++ .../IgniteConfigurationSerializerTest.cs | 554 +++++++++++++++++++ .../dotnet/Apache.Ignite.Core.Tests/app.config | 54 ++ .../Apache.Ignite.Core.csproj | 11 + .../Binary/IBinarySerializer.cs | 6 +- .../IgniteConfigurationSection.cs | 80 +++ .../IgniteConfigurationSection.xsd | 281 ++++++++++ .../dotnet/Apache.Ignite.Core/Ignition.cs | 39 ++ .../Impl/Common/BooleanLowerCaseConverter.cs | 60 ++ .../Common/IgniteConfigurationXmlSerializer.cs | 410 ++++++++++++++ .../Impl/Common/TypeStringConverter.cs | 115 ++++ .../Impl/Events/EventTypeConverter.cs | 133 +++++ 14 files changed, 1814 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/a4d8a049/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj index f5e98c5..fb14ed5 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj @@ -55,6 +55,7 @@ ..\libs\nunit.framework.dll + @@ -117,6 +118,8 @@ + + @@ -251,6 +254,7 @@ + http://git-wip-us.apache.org/repos/asf/ignite/blob/a4d8a049/modules/platforms/dotnet/Apache.Ignite.Core.Tests/FutureTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/FutureTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/FutureTest.cs index f18be8c..bc1f08f 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/FutureTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/FutureTest.cs @@ -67,6 +67,7 @@ namespace Apache.Ignite.Core.Tests [TestFixtureTearDown] public void TestFixtureTearDown() { + Ignition.StopAll(true); TestUtils.KillProcesses(); } http://git-wip-us.apache.org/repos/asf/ignite/blob/a4d8a049/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSectionTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSectionTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSectionTest.cs new file mode 100644 index 0000000..29aea90 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSectionTest.cs @@ -0,0 +1,69 @@ +/* + * 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.Tests +{ + using System; + using System.Configuration; + using System.Linq; + using Apache.Ignite.Core.Impl.Common; + using NUnit.Framework; + + /// + /// Tests . + /// + public class IgniteConfigurationSectionTest + { + /// + /// Tests the read. + /// + [Test] + public void TestRead() + { + var section = (IgniteConfigurationSection) ConfigurationManager.GetSection("igniteConfiguration"); + + Assert.AreEqual("myGrid1", section.IgniteConfiguration.GridName); + Assert.AreEqual("cacheName", section.IgniteConfiguration.CacheConfiguration.Single().Name); + } + + /// + /// Tests the ignite start. + /// + [Test] + public void TestIgniteStart() + { + Environment.SetEnvironmentVariable(Classpath.EnvIgniteNativeTestClasspath, "true"); + + using (var ignite = Ignition.StartFromApplicationConfiguration("igniteConfiguration")) + { + Assert.AreEqual("myGrid1", ignite.Name); + Assert.IsNotNull(ignite.GetCache("cacheName")); + } + + using (var ignite = Ignition.StartFromApplicationConfiguration("igniteConfiguration2")) + { + Assert.AreEqual("myGrid2", ignite.Name); + Assert.IsNotNull(ignite.GetCache("cacheName2")); + } + + using (var ignite = Ignition.StartFromApplicationConfiguration()) + { + Assert.IsTrue(ignite.Name.StartsWith("myGrid")); + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/a4d8a049/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs new file mode 100644 index 0000000..d8c52ee --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs @@ -0,0 +1,554 @@ +/* + * 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. + */ + +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable MemberCanBePrivate.Global +namespace Apache.Ignite.Core.Tests +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Text; + using System.Threading; + using System.Xml; + using System.Xml.Schema; + using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Cache.Configuration; + using Apache.Ignite.Core.Cache.Store; + using Apache.Ignite.Core.Common; + 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.Tests.Binary; + using NUnit.Framework; + + /// + /// Tests serialization. + /// + public class IgniteConfigurationSerializerTest + { + /// + /// Tests the predefined XML. + /// + [Test] + public void TestPredefinedXml() + { + var xml = @" + 127.1.1.1 + + + + Apache.Ignite.Core.Tests.IgniteConfigurationSerializerTest+FooClass, Apache.Ignite.Core.Tests + + + + + + -Xms1g-Xmx4g + + + + + + + + + + + + + + + + + + + + + + + + + + + 42 + TaskFailed + JobFinished + + "; + var reader = XmlReader.Create(new StringReader(xml)); + + var cfg = IgniteConfigurationXmlSerializer.Deserialize(reader); + + Assert.AreEqual("c:", cfg.WorkDirectory); + Assert.AreEqual("127.1.1.1", cfg.Localhost); + Assert.AreEqual(1024, cfg.JvmMaxMemoryMb); + Assert.AreEqual(TimeSpan.FromSeconds(10), cfg.MetricsLogFrequency); + Assert.AreEqual(TimeSpan.FromMinutes(1), ((TcpDiscoverySpi)cfg.DiscoverySpi).JoinTimeout); + Assert.AreEqual(7, + ((TcpDiscoveryMulticastIpFinder) ((TcpDiscoverySpi) cfg.DiscoverySpi).IpFinder).AddressRequestAttempts); + Assert.AreEqual(new[] { "-Xms1g", "-Xmx4g" }, cfg.JvmOptions); + Assert.AreEqual(15, ((LifecycleBean) cfg.LifecycleBeans.Single()).Foo); + Assert.AreEqual("testBar", ((NameMapper) cfg.BinaryConfiguration.DefaultNameMapper).Bar); + Assert.AreEqual( + "Apache.Ignite.Core.Tests.IgniteConfigurationSerializerTest+FooClass, Apache.Ignite.Core.Tests", + cfg.BinaryConfiguration.Types.Single()); + Assert.AreEqual(new[] {42, EventType.TaskFailed, EventType.JobFinished}, cfg.IncludedEventTypes); + + Assert.AreEqual("secondCache", cfg.CacheConfiguration.Last().Name); + + var cacheCfg = cfg.CacheConfiguration.First(); + + Assert.AreEqual(CacheMode.Replicated, cacheCfg.CacheMode); + + var queryEntity = cacheCfg.QueryEntities.Single(); + Assert.AreEqual(typeof(int), queryEntity.KeyType); + Assert.AreEqual(typeof(string), queryEntity.ValueType); + Assert.AreEqual("length", queryEntity.Fields.Single().Name); + Assert.AreEqual(typeof(int), queryEntity.Fields.Single().FieldType); + Assert.AreEqual("somefield.field", queryEntity.Aliases.Single().FullName); + Assert.AreEqual("shortField", queryEntity.Aliases.Single().Alias); + Assert.AreEqual(QueryIndexType.Geospatial, queryEntity.Indexes.Single().IndexType); + Assert.AreEqual("indexFld", queryEntity.Indexes.Single().Fields.Single().Name); + Assert.AreEqual(true, queryEntity.Indexes.Single().Fields.Single().IsDescending); + } + + /// + /// Tests the serialize deserialize. + /// + [Test] + public void TestSerializeDeserialize() + { + // Test custom + CheckSerializeDeserialize(GetTestConfig()); + + // Test custom with different culture to make sure numbers are serialized properly + RunWithCustomCulture(() => CheckSerializeDeserialize(GetTestConfig())); + + // Test default + CheckSerializeDeserialize(new IgniteConfiguration()); + } + + /// + /// Tests the schema validation. + /// + [Test] + public void TestSchemaValidation() + { + CheckSchemaValidation(); + + RunWithCustomCulture(CheckSchemaValidation); + + // Check invalid xml + const string invalidXml = + @" + + "; + + Assert.Throws(() => CheckSchemaValidation(invalidXml)); + } + + /// + /// Checks the schema validation. + /// + private static void CheckSchemaValidation() + { + var sb = new StringBuilder(); + + using (var xmlWriter = XmlWriter.Create(sb)) + { + IgniteConfigurationXmlSerializer.Serialize(GetTestConfig(), xmlWriter, "igniteConfiguration"); + } + + CheckSchemaValidation(sb.ToString()); + } + + /// + /// Checks the schema validation. + /// + /// The XML. + private static void CheckSchemaValidation(string xml) + { + var document = new XmlDocument(); + + document.Schemas.Add("http://ignite.apache.org/schema/dotnet/IgniteConfigurationSection", + XmlReader.Create("IgniteConfigurationSection.xsd")); + + document.Load(new StringReader(xml)); + + document.Validate(null); + } + + /// + /// Checks the serialize deserialize. + /// + /// The config. + private static void CheckSerializeDeserialize(IgniteConfiguration cfg) + { + var resCfg = SerializeDeserialize(cfg); + + AssertReflectionEqual(cfg, resCfg); + } + + /// + /// Serializes and deserializes a config. + /// + private static IgniteConfiguration SerializeDeserialize(IgniteConfiguration cfg) + { + var sb = new StringBuilder(); + + using (var xmlWriter = XmlWriter.Create(sb)) + { + IgniteConfigurationXmlSerializer.Serialize(cfg, xmlWriter, "igniteConfig"); + } + + var xml = sb.ToString(); + + using (var xmlReader = XmlReader.Create(new StringReader(xml))) + { + xmlReader.MoveToContent(); + return IgniteConfigurationXmlSerializer.Deserialize(xmlReader); + } + } + + /// + /// Asserts equality with reflection. + /// + private static void AssertReflectionEqual(object x, object y) + { + var type = x.GetType(); + + Assert.AreEqual(type, y.GetType()); + + if (type.IsValueType || type == typeof (string) || type.IsSubclassOf(typeof (Type))) + { + Assert.AreEqual(x, y); + return; + } + + var props = type.GetProperties(); + + foreach (var propInfo in props) + { + var propType = propInfo.PropertyType; + + var xVal = propInfo.GetValue(x, null); + var yVal = propInfo.GetValue(y, null); + + if (xVal == null || yVal == null) + { + Assert.IsNull(xVal); + Assert.IsNull(yVal); + } + else if (propType != typeof(string) && propType.IsGenericType + && propType.GetGenericTypeDefinition() == typeof (ICollection<>)) + { + var xCol = ((IEnumerable) xVal).OfType().ToList(); + var yCol = ((IEnumerable) yVal).OfType().ToList(); + + Assert.AreEqual(xCol.Count, yCol.Count); + + for (int i = 0; i < xCol.Count; i++) + AssertReflectionEqual(xCol[i], yCol[i]); + } + else + { + AssertReflectionEqual(xVal, yVal); + } + } + } + + /// + /// Gets the test configuration. + /// + private static IgniteConfiguration GetTestConfig() + { + return new IgniteConfiguration + { + GridName = "gridName", + JvmOptions = new[] {"1", "2"}, + Localhost = "localhost11", + JvmClasspath = "classpath", + Assemblies = new[] {"asm1", "asm2", "asm3"}, + BinaryConfiguration = new BinaryConfiguration + { + TypeConfigurations = new[] + { + new BinaryTypeConfiguration + { + IsEnum = true, + KeepDeserialized = true, + AffinityKeyFieldName = "affKeyFieldName", + TypeName = "typeName", + IdMapper = new IdMapper(), + NameMapper = new NameMapper(), + Serializer = new TestSerializer() + } + }, + DefaultIdMapper = new IdMapper(), + DefaultKeepDeserialized = true, + DefaultNameMapper = new NameMapper(), + DefaultSerializer = new TestSerializer() + }, + CacheConfiguration = new[] + { + new CacheConfiguration("cacheName") + { + AtomicWriteOrderMode = CacheAtomicWriteOrderMode.Primary, + AtomicityMode = CacheAtomicityMode.Transactional, + Backups = 15, + CacheMode = CacheMode.Partitioned, + CacheStoreFactory = new TestCacheStoreFactory(), + CopyOnRead = true, + EagerTtl = true, + EnableSwap = true, + EvictSynchronized = true, + EvictSynchronizedConcurrencyLevel = 13, + EvictSynchronizedKeyBufferSize = 14, + EvictSynchronizedTimeout = TimeSpan.FromMinutes(3), + Invalidate = true, + KeepBinaryInStore = true, + LoadPreviousValue = true, + LockTimeout = TimeSpan.FromSeconds(56), + LongQueryWarningTimeout = TimeSpan.FromSeconds(99), + MaxConcurrentAsyncOperations = 24, + MaxEvictionOverflowRatio = 5.6F, + MemoryMode = CacheMemoryMode.OffheapValues, + OffHeapMaxMemory = 567, + QueryEntities = new[] + { + new QueryEntity + { + Fields = new[] + { + new QueryField("field", typeof (int)) + }, + Indexes = new[] + { + new QueryIndex("field") { IndexType = QueryIndexType.FullText } + }, + Aliases = new[] + { + new QueryAlias("field.field", "fld") + }, + KeyType = typeof (string), + ValueType = typeof (long) + }, + }, + ReadFromBackup = true, + RebalanceBatchSize = 33, + RebalanceDelay = TimeSpan.MaxValue, + RebalanceMode = CacheRebalanceMode.Sync, + RebalanceThrottle = TimeSpan.FromHours(44), + RebalanceTimeout = TimeSpan.FromMinutes(8), + SqlEscapeAll = true, + SqlOnheapRowCacheSize = 679, + StartSize = 1023, + WriteBehindBatchSize = 45, + WriteBehindEnabled = true, + WriteBehindFlushFrequency = TimeSpan.FromSeconds(5), + WriteBehindFlushSize = 66, + WriteBehindFlushThreadCount = 2, + WriteSynchronizationMode = CacheWriteSynchronizationMode.FullAsync + } + }, + ClientMode = true, + DiscoverySpi = new TcpDiscoverySpi + { + NetworkTimeout = TimeSpan.FromSeconds(1), + SocketTimeout = TimeSpan.FromSeconds(2), + AckTimeout = TimeSpan.FromSeconds(3), + JoinTimeout = TimeSpan.FromSeconds(4), + MaxAckTimeout = TimeSpan.FromSeconds(5), + IpFinder = new TcpDiscoveryMulticastIpFinder + { + TimeToLive = 110, + MulticastGroup = "multicastGroup", + AddressRequestAttempts = 10, + MulticastPort = 987, + ResponseTimeout = TimeSpan.FromDays(1), + LocalAddress = "127.0.0.2", + Endpoints = new[] {"", "abc"} + } + }, + IgniteHome = "igniteHome", + IncludedEventTypes = EventType.CacheQueryAll, + JvmDllPath = @"c:\jvm", + JvmInitialMemoryMb = 1024, + JvmMaxMemoryMb = 2048, + LifecycleBeans = new[] {new LifecycleBean(), new LifecycleBean() }, + MetricsExpireTime = TimeSpan.FromSeconds(15), + MetricsHistorySize = 45, + MetricsLogFrequency = TimeSpan.FromDays(2), + MetricsUpdateFrequency = TimeSpan.MinValue, + NetworkSendRetryCount = 7, + NetworkSendRetryDelay = TimeSpan.FromSeconds(98), + NetworkTimeout = TimeSpan.FromMinutes(4), + SuppressWarnings = true, + WorkDirectory = @"c:\work" + }; + } + + /// + /// Runs the with custom culture. + /// + /// The action. + private static void RunWithCustomCulture(Action action) + { + RunWithCulture(action, CultureInfo.InvariantCulture); + RunWithCulture(action, CultureInfo.GetCultureInfo("ru-RU")); + } + + /// + /// Runs the with culture. + /// + /// The action. + /// The culture information. + private static void RunWithCulture(Action action, CultureInfo cultureInfo) + { + var oldCulture = Thread.CurrentThread.CurrentCulture; + + try + { + Thread.CurrentThread.CurrentCulture = cultureInfo; + + action(); + } + finally + { + Thread.CurrentThread.CurrentCulture = oldCulture; + } + } + + /// + /// Test bean. + /// + public class LifecycleBean : ILifecycleBean + { + /// + /// Gets or sets the foo. + /// + /// + /// The foo. + /// + public int Foo { get; set; } + + /// + /// This method is called when lifecycle event occurs. + /// + /// Lifecycle event. + public void OnLifecycleEvent(LifecycleEventType evt) + { + // No-op. + } + } + + /// + /// Test mapper. + /// + public class NameMapper : IBinaryNameMapper + { + /// + /// Gets or sets the bar. + /// + /// + /// The bar. + /// + public string Bar { get; set; } + + /// + /// Gets the type name. + /// + /// The name. + /// + /// Type name. + /// + public string GetTypeName(string name) + { + return name; + } + + /// + /// Gets the field name. + /// + /// The name. + /// + /// Field name. + /// + public string GetFieldName(string name) + { + return name; + } + } + + /// + /// Serializer. + /// + public class TestSerializer : IBinarySerializer + { + /// + /// Write portalbe object. + /// + /// Object. + /// Poratble writer. + public void WriteBinary(object obj, IBinaryWriter writer) + { + // No-op. + } + + /// + /// Read binary object. + /// + /// Instantiated empty object. + /// Poratble reader. + public void ReadBinary(object obj, IBinaryReader reader) + { + // No-op. + } + } + + /// + /// Test class. + /// + public class FooClass + { + // No-op. + } + + /// + /// Test factory. + /// + public class TestCacheStoreFactory : IFactory + { + /// + /// Creates an instance of the cache store. + /// + /// + /// New instance of the cache store. + /// + public ICacheStore CreateInstance() + { + return null; + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/a4d8a049/modules/platforms/dotnet/Apache.Ignite.Core.Tests/app.config ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/app.config b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/app.config new file mode 100644 index 0000000..c290c83 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/app.config @@ -0,0 +1,54 @@ + + + + + + +
+
+ + + + + + + 127.0.0.1:47500..47501 + + + + + + + + + + + + + + 127.0.0.1:47500..47501 + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/ignite/blob/a4d8a049/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj index e2efd0a..d0ef352 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj @@ -60,7 +60,9 @@ + + @@ -183,6 +185,7 @@ + @@ -222,11 +225,13 @@ + + @@ -234,10 +239,12 @@ + + @@ -434,6 +441,10 @@ + + Designer + Always + http://git-wip-us.apache.org/repos/asf/ignite/blob/a4d8a049/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinarySerializer.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinarySerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinarySerializer.cs index 23dc811..3f924eb 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinarySerializer.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinarySerializer.cs @@ -23,17 +23,17 @@ namespace Apache.Ignite.Core.Binary public interface IBinarySerializer { /// - /// Write portalbe object. + /// Write binary object. /// /// Object. - /// Poratble writer. + /// Binary writer. void WriteBinary(object obj, IBinaryWriter writer); /// /// Read binary object. /// /// Instantiated empty object. - /// Poratble reader. + /// Binary reader. void ReadBinary(object obj, IBinaryReader reader); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/a4d8a049/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.cs new file mode 100644 index 0000000..51b963e --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.cs @@ -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 +{ + using System.Configuration; + using System.Text; + using System.Xml; + using Apache.Ignite.Core.Impl.Common; + + /// + /// Ignite configuration section for app.config and web.config files. + /// + public class IgniteConfigurationSection : ConfigurationSection + { + /// + /// Gets or sets the ignite configuration. + /// + /// + /// The ignite configuration. + /// + public IgniteConfiguration IgniteConfiguration { get; private set; } + + /// + /// Reads XML from the configuration file. + /// + /// The reader object, which reads from the configuration file. + protected override void DeserializeSection(XmlReader reader) + { + IgniteArgumentCheck.NotNull(reader, "reader"); + + IgniteConfiguration = IgniteConfigurationXmlSerializer.Deserialize(reader); + } + + /// + /// Creates an XML string containing an unmerged view of the + /// object as a single section to write to a file. + /// + /// The + /// instance to use as the parent when performing the un-merge. + /// The name of the section to create. + /// The instance + /// to use when writing to a string. + /// + /// An XML string containing an unmerged view of the object. + /// + protected override string SerializeSection(ConfigurationElement parentElement, string name, + ConfigurationSaveMode saveMode) + { + IgniteArgumentCheck.NotNull(parentElement, "parentElement"); + IgniteArgumentCheck.NotNullOrEmpty(name, "name"); + + if (IgniteConfiguration == null) + return string.Format("<{0} />", name); + + var sb = new StringBuilder(); + + using (var xmlWriter = XmlWriter.Create(sb)) + { + IgniteConfigurationXmlSerializer.Serialize(IgniteConfiguration, xmlWriter, name); + + return sb.ToString(); + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/a4d8a049/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd new file mode 100644 index 0000000..5181217 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd @@ -0,0 +1,281 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/ignite/blob/a4d8a049/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs index 0549010..70d7422 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs @@ -20,6 +20,7 @@ namespace Apache.Ignite.Core { using System; using System.Collections.Generic; + using System.Configuration; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -116,6 +117,44 @@ namespace Apache.Ignite.Core } /// + /// Reads from first in the + /// application configuration and starts Ignite. + /// + /// Started Ignite. + public static IIgnite StartFromApplicationConfiguration() + { + var cfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); + + var section = cfg.Sections.OfType().FirstOrDefault(); + + if (section == null) + throw new ConfigurationErrorsException( + string.Format("Could not find {0} in current application configuration", + typeof(IgniteConfigurationSection).Name)); + + return Start(section.IgniteConfiguration); + } + + /// + /// Reads from application configuration + /// with specified name and starts Ignite. + /// + /// Name of the section. + /// Started Ignite. + public static IIgnite StartFromApplicationConfiguration(string sectionName) + { + IgniteArgumentCheck.NotNullOrEmpty(sectionName, "sectionName"); + + var section = ConfigurationManager.GetSection(sectionName) as IgniteConfigurationSection; + + if (section == null) + throw new ConfigurationErrorsException(string.Format("Could not find {0} with name '{1}'", + typeof(IgniteConfigurationSection).Name, sectionName)); + + return Start(section.IgniteConfiguration); + } + + /// /// Starts Ignite with given configuration. /// /// Started Ignite. http://git-wip-us.apache.org/repos/asf/ignite/blob/a4d8a049/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/BooleanLowerCaseConverter.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/BooleanLowerCaseConverter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/BooleanLowerCaseConverter.cs new file mode 100644 index 0000000..e8cced2 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/BooleanLowerCaseConverter.cs @@ -0,0 +1,60 @@ +/* + * 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.Impl.Common +{ + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + + /// + /// Bollean converter that returns lower-case strings, for XML serialization. + /// + internal class BooleanLowerCaseConverter : BooleanConverter + { + /// + /// Default instance. + /// + public static readonly BooleanLowerCaseConverter Instance = new BooleanLowerCaseConverter(); + + /// + /// Converts the given value object to the specified type, using the specified context and culture information. + /// + /// An that provides a format context. + /// + /// A . If null is passed, the current culture is assumed. + /// + /// The to convert. + /// + /// The to convert the parameter to. + /// + /// + /// An that represents the converted value. + /// + [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")] + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "2")] + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, + Type destinationType) + { + if (destinationType == typeof (string)) + return value.ToString().ToLowerInvariant(); + + return base.ConvertTo(context, culture, value, destinationType); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/a4d8a049/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs new file mode 100644 index 0000000..af25bfa --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs @@ -0,0 +1,410 @@ +/* + * 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.Impl.Common +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.ComponentModel; + using System.Configuration; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Linq; + using System.Reflection; + using System.Xml; + using Apache.Ignite.Core.Impl.Events; + + /// + /// Serializes to XML. + /// + internal static class IgniteConfigurationXmlSerializer + { + /** Attribute that specifies a type for abstract properties, such as IpFinder. */ + private const string TypNameAttribute = "type"; + + /** Xmlns. */ + private const string XmlnsAttribute = "xmlns"; + + /** Schema. */ + private const string Schema = "http://ignite.apache.org/schema/dotnet/IgniteConfigurationSection"; + + /// + /// Deserializes from specified . + /// + /// The reader. + /// Resulting . + public static IgniteConfiguration Deserialize(XmlReader reader) + { + IgniteArgumentCheck.NotNull(reader, "reader"); + + var cfg = new IgniteConfiguration(); + + if (reader.NodeType == XmlNodeType.Element || reader.Read()) + ReadElement(reader, cfg); + + return cfg; + } + + /// + /// Serializes specified to . + /// + /// The configuration. + /// The writer. + /// Name of the root element. + public static void Serialize(IgniteConfiguration configuration, XmlWriter writer, string rootElementName) + { + IgniteArgumentCheck.NotNull(configuration, "configuration"); + IgniteArgumentCheck.NotNull(writer, "writer"); + IgniteArgumentCheck.NotNullOrEmpty(rootElementName, "rootElementName"); + + WriteElement(configuration, writer, rootElementName, typeof(IgniteConfiguration)); + } + + /// + /// Writes new element. + /// + private static void WriteElement(object obj, XmlWriter writer, string rootElementName, Type valueType, + PropertyInfo property = null) + { + if (valueType == typeof(IgniteConfiguration)) + writer.WriteStartElement(rootElementName, Schema); // write xmlns for the root element + else + writer.WriteStartElement(rootElementName); + + if (IsBasicType(valueType)) + WriteBasicProperty(obj, writer, valueType, property); + else if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof (ICollection<>)) + WriteCollectionProperty(obj, writer, valueType, property); + else + WriteComplexProperty(obj, writer, valueType); + + writer.WriteEndElement(); + } + + /// + /// Writes the property of a basic type (primitives, strings, types). + /// + [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] + private static void WriteBasicProperty(object obj, XmlWriter writer, Type valueType, PropertyInfo property) + { + var converter = GetConverter(property, valueType); + + var stringValue = converter.ConvertToInvariantString(obj); + + writer.WriteString(stringValue); + } + + /// + /// Writes the collection property. + /// + private static void WriteCollectionProperty(object obj, XmlWriter writer, Type valueType, PropertyInfo property) + { + var elementType = valueType.GetGenericArguments().Single(); + + var elementTypeName = PropertyNameToXmlName(elementType.Name); + + foreach (var element in (IEnumerable)obj) + WriteElement(element, writer, elementTypeName, elementType, property); + } + + /// + /// Writes the complex property (nested object). + /// + [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] + private static void WriteComplexProperty(object obj, XmlWriter writer, Type valueType) + { + var props = GetNonDefaultProperties(obj).ToList(); + + // Specify type for interfaces and abstract classes + if (valueType.IsAbstract) + writer.WriteAttributeString(TypNameAttribute, TypeStringConverter.Convert(obj.GetType())); + + // Write attributes + foreach (var prop in props.Where(p => IsBasicType(p.PropertyType))) + { + var converter = GetConverter(prop, prop.PropertyType); + var stringValue = converter.ConvertToInvariantString(prop.GetValue(obj, null)); + writer.WriteAttributeString(PropertyNameToXmlName(prop.Name), stringValue); + } + + // Write elements + foreach (var prop in props.Where(p => !IsBasicType(p.PropertyType))) + WriteElement(prop.GetValue(obj, null), writer, PropertyNameToXmlName(prop.Name), + prop.PropertyType, prop); + } + + /// + /// Reads the element. + /// + private static void ReadElement(XmlReader reader, object target) + { + var targetType = target.GetType(); + + // Read attributes + while (reader.MoveToNextAttribute()) + { + var name = reader.Name; + var val = reader.Value; + + SetProperty(target, name, val); + } + + // Read content + reader.MoveToElement(); + + while (reader.Read()) + { + if (reader.NodeType != XmlNodeType.Element) + continue; + + var name = reader.Name; + var prop = GetPropertyOrThrow(name, reader.Value, targetType); + var propType = prop.PropertyType; + + if (IsBasicType(propType)) + { + // Regular property in xmlElement form + SetProperty(target, name, reader.ReadString()); + } + else if (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof (ICollection<>)) + { + // Collection + ReadCollectionProperty(reader, prop, target); + } + else + { + // Nested object (complex property) + prop.SetValue(target, ReadComplexProperty(reader, propType, prop.Name, targetType), null); + } + } + } + + /// + /// Reads the complex property (nested object). + /// + private static object ReadComplexProperty(XmlReader reader, Type propType, string propName, Type targetType) + { + if (propType.IsAbstract) + { + var typeName = reader.GetAttribute(TypNameAttribute); + + var derivedTypes = GetConcreteDerivedTypes(propType); + + propType = typeName == null + ? null + : Type.GetType(typeName, false) ?? derivedTypes.FirstOrDefault(x => x.Name == typeName); + + if (propType == null) + { + var message = string.Format("'type' attribute is required for '{0}.{1}' property", targetType.Name, + propName); + + if (typeName != null) + { + message += ", specified type cannot be resolved: " + typeName; + } + else if (derivedTypes.Any()) + message += ", possible values are: " + string.Join(", ", derivedTypes.Select(x => x.Name)); + + throw new ConfigurationErrorsException(message); + } + } + + var nestedVal = Activator.CreateInstance(propType); + + using (var subReader = reader.ReadSubtree()) + { + subReader.Read(); // read first element + + ReadElement(subReader, nestedVal); + } + + return nestedVal; + } + + /// + /// Reads the collection. + /// + private static void ReadCollectionProperty(XmlReader reader, PropertyInfo prop, object target) + { + var elementType = prop.PropertyType.GetGenericArguments().Single(); + + var listType = typeof (List<>).MakeGenericType(elementType); + + var list = (IList) Activator.CreateInstance(listType); + + var converter = IsBasicType(elementType) ? GetConverter(prop, elementType) : null; + + using (var subReader = reader.ReadSubtree()) + { + subReader.Read(); // skip list head + while (subReader.Read()) + { + if (subReader.NodeType != XmlNodeType.Element) + continue; + + if (subReader.Name != PropertyNameToXmlName(elementType.Name)) + throw new ConfigurationErrorsException( + string.Format("Invalid list element in IgniteConfiguration: expected '{0}', but was '{1}'", + PropertyNameToXmlName(elementType.Name), subReader.Name)); + + list.Add(converter != null + ? converter.ConvertFromInvariantString(subReader.ReadString()) + : ReadComplexProperty(subReader, elementType, prop.Name, target.GetType())); + } + } + + prop.SetValue(target, list, null); + } + + /// + /// Sets the property. + /// + private static void SetProperty(object target, string propName, string propVal) + { + if (propName == TypNameAttribute || propName == XmlnsAttribute) + return; + + var type = target.GetType(); + var property = GetPropertyOrThrow(propName, propVal, type); + + var converter = GetConverter(property, property.PropertyType); + + var convertedVal = converter.ConvertFromInvariantString(propVal); + + property.SetValue(target, convertedVal, null); + } + + /// + /// Gets concrete derived types. + /// + private static List GetConcreteDerivedTypes(Type type) + { + return type.Assembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && type.IsAssignableFrom(t)).ToList(); + } + + /// + /// Gets specified property from a type or throws an exception. + /// + private static PropertyInfo GetPropertyOrThrow(string propName, string propVal, Type type) + { + var property = type.GetProperty(XmlNameToPropertyName(propName)); + + if (property == null) + throw new ConfigurationErrorsException( + string.Format( + "Invalid IgniteConfiguration attribute '{0}={1}', there is no such property on '{2}'", + propName, propVal, type)); + + return property; + } + + /// + /// Converts an XML name to CLR name. + /// + private static string XmlNameToPropertyName(string name) + { + Debug.Assert(name.Length > 0); + + if (name == "int") + return "Int32"; // allow aliases + + return char.ToUpperInvariant(name[0]) + name.Substring(1); + } + + /// + /// Converts a CLR name to XML name. + /// + private static string PropertyNameToXmlName(string name) + { + Debug.Assert(name.Length > 0); + + if (name == "Int32") + return "int"; // allow aliases + + return char.ToLowerInvariant(name[0]) + name.Substring(1); + } + + /// + /// Determines whether specified type is a basic built-in type. + /// + private static bool IsBasicType(Type propertyType) + { + Debug.Assert(propertyType != null); + + return propertyType.IsValueType || propertyType == typeof(string) || propertyType == typeof(Type); + } + + /// + /// Gets converter for a property. + /// + private static TypeConverter GetConverter(PropertyInfo property, Type propertyType) + { + Debug.Assert(property != null); + Debug.Assert(propertyType != null); + + if (propertyType.IsEnum) + return new GenericEnumConverter(propertyType); + + if (propertyType == typeof (Type)) + return TypeStringConverter.Instance; + + if (propertyType == typeof(bool)) + return BooleanLowerCaseConverter.Instance; + + if (property.DeclaringType == typeof (IgniteConfiguration) && property.Name == "IncludedEventTypes") + return EventTypeConverter.Instance; + + var converter = TypeDescriptor.GetConverter(propertyType); + + if (converter == null || !converter.CanConvertFrom(typeof(string)) || + !converter.CanConvertTo(typeof(string))) + throw new ConfigurationErrorsException("No converter for type " + propertyType); + + return converter; + } + + /// + /// Gets properties with non-default value. + /// + private static IEnumerable GetNonDefaultProperties(object obj) + { + Debug.Assert(obj != null); + + return obj.GetType().GetProperties().Where(p => !Equals(p.GetValue(obj, null), GetDefaultValue(p))); + } + + /// + /// Gets the default value for a property. + /// + private static object GetDefaultValue(PropertyInfo property) + { + var attr = property.GetCustomAttributes(true).OfType().FirstOrDefault(); + + if (attr != null) + return attr.Value; + + var propertyType = property.PropertyType; + + if (propertyType.IsValueType) + return Activator.CreateInstance(propertyType); + + return null; + } + } +}