ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From voze...@apache.org
Subject ignite git commit: IGNITE-3020 .NET: Ensured that Windows service is stopped correctly in case of forceful node stop. This closes #679.
Date Wed, 11 May 2016 15:21:46 GMT
Repository: ignite
Updated Branches:
  refs/heads/ignite-1.6 80979dfcd -> b50eb654c


IGNITE-3020 .NET: Ensured that Windows service is stopped correctly in case of forceful node stop. This closes #679.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/b50eb654
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/b50eb654
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/b50eb654

Branch: refs/heads/ignite-1.6
Commit: b50eb654c72bf3f318a5e4d2a8871607c96c0cba
Parents: 80979df
Author: Pavel Tupitsyn <ptupitsyn@gridgain.com>
Authored: Wed May 11 18:21:32 2016 +0300
Committer: vozerov-gridgain <vozerov@gridgain.com>
Committed: Wed May 11 18:21:32 2016 +0300

----------------------------------------------------------------------
 .gitignore                                      |  42 ++-
 .../internal/binary/BinaryClassDescriptor.java  |  43 ++-
 .../ignite/internal/binary/BinaryContext.java   |  90 +++---
 .../internal/binary/BinaryReaderExImpl.java     |  15 +-
 .../binary/GridBinaryWildcardsSelfTest.java     |  53 ++--
 ...acheBinaryObjectUserClassloaderSelfTest.java | 274 +++++++++++++++++++
 .../marshaller/MarshallerContextTestImpl.java   |   7 +
 .../testframework/junits/GridAbstractTest.java  |   3 +-
 .../IgniteBinaryObjectsTestSuite.java           |   3 +
 .../Apache.Ignite.Core.Tests.csproj             |   2 +
 .../WindowsServiceTest.cs                       | 124 +++++++++
 .../dotnet/Apache.Ignite.Core/Impl/Ignite.cs    |   6 +
 .../Impl/Unmanaged/UnmanagedCallbacks.cs        |   6 +
 .../dotnet/Apache.Ignite/Apache.Ignite.csproj   |   5 +-
 .../dotnet/Apache.Ignite/Config/Configurator.cs |   5 +
 .../Apache.Ignite/Service/IgniteService.cs      | 102 +++----
 .../Service/IgniteServiceInstaller.cs           |  64 +++++
 .../Apache.Ignite/Service/NativeMethods.cs      |  57 ----
 18 files changed, 699 insertions(+), 202 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index f36b1d6..665770d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,8 +8,6 @@ xcuserdata/
 .DS_Store
 /bamboo/TEST*.xml
 /bamboo/junit*.properties
-*.suo
-*.csproj.user
 *.o
 *.lo
 *.obj
@@ -21,16 +19,42 @@ target
 pom-installed.xml
 git-patch-prop-local.sh
 /slurp.sh
-*.vcxproj.user
-*.sdf
-*.opensdf
-*.opendb
 **/cpp/**/vs/x64/
 **/cpp/**/vs/Win32/
-**/dotnet/**/obj/
-**/dotnet/**/bin/
 /modules/platforms/cpp/doc/
 .settings
 .classpath
 .project
-/modules/platforms/**/*.VC.db
\ No newline at end of file
+/modules/platforms/**/*.VC.db
+**/dotnet/libs/
+
+#Visual Studio files
+*.[Oo]bj
+*.user
+*.aps
+*.pch
+*.vspscc
+*.vssscc
+*_i.c
+*_p.c
+*.ncb
+*.suo
+*.tlb
+*.tlh
+*.bak
+*.[Cc]ache
+*.ilk
+*.log
+*.lib
+*.sbr
+*.sdf
+*.opensdf
+*.db
+*.opendb
+ipch/
+[Oo]bj/
+[Bb]in
+[Dd]ebug*/
+[Rr]elease*/
+packages
+*.classname

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java
index d32b99a..d2d715b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java
@@ -62,6 +62,9 @@ public class BinaryClassDescriptor {
     /** Configured serializer. */
     private final BinarySerializer serializer;
 
+    /** Serializer that is passed during BinaryClassDescriptor construction. Can differ from {@link #serializer}. */
+    private final BinarySerializer initialSerializer;
+
     /** ID mapper. */
     private final BinaryInternalMapper mapper;
 
@@ -142,6 +145,8 @@ public class BinaryClassDescriptor {
         assert cls != null;
         assert mapper != null;
 
+        initialSerializer = serializer;
+
         // If serializer is not defined at this point, then we have to user OptimizedMarshaller.
         useOptMarshaller = serializer == null;
 
@@ -383,9 +388,45 @@ public class BinaryClassDescriptor {
     }
 
     /**
+     * @return Type name.
+     */
+    String typeName() {
+        return typeName;
+    }
+
+    /**
+     * @return Type mapper.
+     */
+    BinaryInternalMapper mapper() {
+        return mapper;
+    }
+
+    /**
+     * @return Serializer.
+     */
+    BinarySerializer serializer() {
+        return serializer;
+    }
+
+    /**
+     * @return Initial serializer that is passed during BinaryClassDescriptor construction.
+     * Can differ from {@link #serializer}.
+     */
+    BinarySerializer initialSerializer() {
+        return initialSerializer;
+    }
+
+    /**
+     * @return Affinity field key name.
+     */
+    String affFieldKeyName() {
+        return affKeyFieldName;
+    }
+
+    /**
      * @return User type flag.
      */
-    public boolean userType() {
+    boolean userType() {
         return userType;
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
index 8754795..daf34ad 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
@@ -17,7 +17,6 @@
 
 package org.apache.ignite.internal.binary;
 
-import java.io.Externalizable;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Field;
@@ -99,8 +98,8 @@ import org.jsr166.ConcurrentHashMap8;
  * Binary context.
  */
 public class BinaryContext {
-    /** */
-    private static final ClassLoader dfltLdr = U.gridClassLoader();
+    /** System loader.*/
+    private static final ClassLoader sysLdr = U.gridClassLoader();
 
     /** */
     private static final BinaryInternalMapper DFLT_MAPPER =
@@ -154,9 +153,6 @@ public class BinaryContext {
     /** */
     private final ConcurrentMap<Class<?>, BinaryClassDescriptor> descByCls = new ConcurrentHashMap8<>();
 
-    /** Holds classes loaded by default class loader only. */
-    private final ConcurrentMap<Integer, BinaryClassDescriptor> userTypes = new ConcurrentHashMap8<>();
-
     /** */
     private final Map<Integer, BinaryClassDescriptor> predefinedTypes = new HashMap<>();
 
@@ -203,13 +199,6 @@ public class BinaryContext {
     private volatile Map<Integer, BinarySchemaRegistry> schemas;
 
     /**
-     * For {@link Externalizable}.
-     */
-    public BinaryContext() {
-        // No-op.
-    }
-
-    /**
      * @param metaHnd Meta data handler.
      * @param igniteCfg Ignite configuration.
      * @param log Logger.
@@ -570,8 +559,13 @@ public class BinaryContext {
 
         BinaryClassDescriptor desc = descByCls.get(cls);
 
-        if (desc == null || !desc.registered())
+        if (desc == null)
             desc = registerClassDescriptor(cls, deserialize);
+        else if (!desc.registered()) {
+            assert desc.userType();
+
+            desc = registerUserClassDescriptor(desc);
+        }
 
         return desc;
     }
@@ -597,16 +591,7 @@ public class BinaryContext {
             return desc;
 
         if (ldr == null)
-            ldr = dfltLdr;
-
-        // If the type hasn't been loaded by default class loader then we mustn't return the descriptor from here
-        // giving a chance to a custom class loader to reload type's class.
-        if (userType && ldr.equals(dfltLdr)) {
-            desc = userTypes.get(typeId);
-
-            if (desc != null)
-                return desc;
-        }
+            ldr = sysLdr;
 
         Class cls;
 
@@ -617,14 +602,14 @@ public class BinaryContext {
         }
         catch (ClassNotFoundException e) {
             // Class might have been loaded by default class loader.
-            if (userType && !ldr.equals(dfltLdr) && (desc = descriptorForTypeId(true, typeId, dfltLdr, deserialize)) != null)
+            if (userType && !ldr.equals(sysLdr) && (desc = descriptorForTypeId(true, typeId, sysLdr, deserialize)) != null)
                 return desc;
 
             throw new BinaryInvalidTypeException(e);
         }
         catch (IgniteCheckedException e) {
             // Class might have been loaded by default class loader.
-            if (userType && !ldr.equals(dfltLdr) && (desc = descriptorForTypeId(true, typeId, dfltLdr, deserialize)) != null)
+            if (userType && !ldr.equals(sysLdr) && (desc = descriptorForTypeId(true, typeId, sysLdr, deserialize)) != null)
                 return desc;
 
             throw new BinaryObjectException("Failed resolve class for ID: " + typeId, e);
@@ -727,11 +712,6 @@ public class BinaryContext {
                 new BinaryMetadata(typeId, typeName, desc.fieldsMeta(), affFieldName, schemas, desc.isEnum()).wrap(this));
         }
 
-        // perform put() instead of putIfAbsent() because "registered" flag might have been changed or class loader
-        // might have reloaded described class.
-        if (IgniteUtils.detectClassLoader(cls).equals(dfltLdr))
-            userTypes.put(typeId, desc);
-
         descByCls.put(cls, desc);
 
         typeId2Mapper.putIfAbsent(typeId, mapper);
@@ -740,6 +720,47 @@ public class BinaryContext {
     }
 
     /**
+     * Creates and registers {@link BinaryClassDescriptor} for the given user {@code class}.
+     *
+     * @param desc Old descriptor that should be re-registered.
+     * @return Class descriptor.
+     */
+    private BinaryClassDescriptor registerUserClassDescriptor(BinaryClassDescriptor desc) {
+        boolean registered;
+
+        try {
+            registered = marshCtx.registerClass(desc.typeId(), desc.describedClass());
+        }
+        catch (IgniteCheckedException e) {
+            throw new BinaryObjectException("Failed to register class.", e);
+        }
+
+        if (registered) {
+            BinarySerializer serializer = desc.initialSerializer();
+
+            if (serializer == null)
+                serializer = serializerForClass(desc.describedClass());
+
+            desc = new BinaryClassDescriptor(
+                this,
+                desc.describedClass(),
+                true,
+                desc.typeId(),
+                desc.typeName(),
+                desc.affFieldKeyName(),
+                desc.mapper(),
+                serializer,
+                true,
+                true
+            );
+
+            descByCls.put(desc.describedClass(), desc);
+        }
+
+        return desc;
+    }
+
+    /**
      * Get serializer for class taking in count default one.
      *
      * @param cls Class.
@@ -996,7 +1017,7 @@ public class BinaryContext {
         Class<?> cls = null;
 
         try {
-            cls = Class.forName(clsName);
+            cls = U.resolveClassLoader(configuration()).loadClass(clsName);
         }
         catch (ClassNotFoundException | NoClassDefFoundError ignored) {
             // No-op.
@@ -1042,15 +1063,12 @@ public class BinaryContext {
                 mapper,
                 serializer,
                 true,
-                true /* registered */
+                false
             );
 
             fieldsMeta = desc.fieldsMeta();
             schemas = desc.schema() != null ? Collections.singleton(desc.schema()) : null;
 
-            if (IgniteUtils.detectClassLoader(cls).equals(dfltLdr))
-                userTypes.put(id, desc);
-
             descByCls.put(cls, desc);
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
index 69aecbf..194b1be 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
@@ -114,6 +114,9 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Bina
     /** Footer end. */
     private final int footerLen;
 
+    /** Class descriptor. */
+    private BinaryClassDescriptor desc;
+
     /** Mapper. */
     private final BinaryInternalMapper mapper;
 
@@ -254,7 +257,9 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Bina
 
                 if (forUnmarshal) {
                     // Registers class by type ID, at least locally if the cache is not ready yet.
-                    typeId = ctx.descriptorForClass(BinaryUtils.doReadClass(in, ctx, ldr, typeId0), false).typeId();
+                    desc = ctx.descriptorForClass(BinaryUtils.doReadClass(in, ctx, ldr, typeId0), false);
+
+                    typeId = desc.typeId();
                 }
                 else
                     typeId = ctx.typeId(BinaryUtils.doReadClassName(in));
@@ -300,7 +305,10 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Bina
      * @return Descriptor.
      */
     BinaryClassDescriptor descriptor() {
-        return ctx.descriptorForTypeId(userType, typeId, ldr, true);
+        if (desc == null)
+            desc = ctx.descriptorForTypeId(userType, typeId, ldr, true);
+
+        return desc;
     }
 
     /**
@@ -1462,7 +1470,8 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Bina
                 break;
 
             case OBJ:
-                BinaryClassDescriptor desc = ctx.descriptorForTypeId(userType, typeId, ldr, true);
+                if (desc == null)
+                    desc = ctx.descriptorForTypeId(userType, typeId, ldr, true);
 
                 streamPosition(dataStart);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/core/src/test/java/org/apache/ignite/internal/binary/GridBinaryWildcardsSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/binary/GridBinaryWildcardsSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/binary/GridBinaryWildcardsSelfTest.java
index d0d63b3..f69cea4 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/binary/GridBinaryWildcardsSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/binary/GridBinaryWildcardsSelfTest.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.binary;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.binary.BinaryBasicIdMapper;
 import org.apache.ignite.binary.BinaryIdMapper;
@@ -84,13 +85,13 @@ public class GridBinaryWildcardsSelfTest extends GridCommonAbstractTest {
 
         BinaryContext ctx = binaryContext(marsh);
 
-        Map<Integer, Class> typeIds = U.field(ctx, "userTypes");
+        ConcurrentMap<Integer, BinaryInternalMapper> types = U.field(ctx, "typeId2Mapper");
 
-        assertEquals(3, typeIds.size());
+        assertEquals(3, types.size());
 
-        assertTrue(typeIds.containsKey(typeId(CLASS1_FULL_NAME, nameMapper, mapper)));
-        assertTrue(typeIds.containsKey(typeId(CLASS2_FULL_NAME, nameMapper, mapper)));
-        assertTrue(typeIds.containsKey(typeId(INNER_CLASS_FULL_NAME, nameMapper, mapper)));
+        assertTrue(types.containsKey(typeId(CLASS1_FULL_NAME, nameMapper, mapper)));
+        assertTrue(types.containsKey(typeId(CLASS2_FULL_NAME, nameMapper, mapper)));
+        assertTrue(types.containsKey(typeId(INNER_CLASS_FULL_NAME, nameMapper, mapper)));
     }
 
     /**
@@ -157,13 +158,13 @@ public class GridBinaryWildcardsSelfTest extends GridCommonAbstractTest {
 
         BinaryContext ctx = binaryContext(marsh);
 
-        Map<Integer, Class> typeIds = U.field(ctx, "userTypes");
+        ConcurrentMap<Integer, BinaryInternalMapper> types = U.field(ctx, "typeId2Mapper");
 
-        assertEquals(3, typeIds.size());
+        assertEquals(3, types.size());
 
-        assertTrue(typeIds.containsKey(typeId(CLASS1_FULL_NAME, nameMapper, idMapper)));
-        assertTrue(typeIds.containsKey(typeId(CLASS2_FULL_NAME, nameMapper, idMapper)));
-        assertTrue(typeIds.containsKey(typeId(INNER_CLASS_FULL_NAME, nameMapper, idMapper)));
+        assertTrue(types.containsKey(typeId(CLASS1_FULL_NAME, nameMapper, idMapper)));
+        assertTrue(types.containsKey(typeId(CLASS2_FULL_NAME, nameMapper, idMapper)));
+        assertTrue(types.containsKey(typeId(INNER_CLASS_FULL_NAME, nameMapper, idMapper)));
     }
 
     /**
@@ -346,13 +347,13 @@ public class GridBinaryWildcardsSelfTest extends GridCommonAbstractTest {
 
         BinaryContext ctx = binaryContext(marsh);
 
-        Map<Integer, Class> typeIds = U.field(ctx, "userTypes");
+        ConcurrentMap<Integer, BinaryInternalMapper> types = U.field(ctx, "typeId2Mapper");
 
-        assertEquals(3, typeIds.size());
+        assertEquals(3, types.size());
 
-        assertTrue(typeIds.containsKey(typeId(CLASS1_FULL_NAME, nameMapper, mapper)));
-        assertTrue(typeIds.containsKey(typeId(INNER_CLASS_FULL_NAME, nameMapper, mapper)));
-        assertTrue(typeIds.containsKey("type2".hashCode()));
+        assertTrue(types.containsKey(typeId(CLASS1_FULL_NAME, nameMapper, mapper)));
+        assertTrue(types.containsKey(typeId(INNER_CLASS_FULL_NAME, nameMapper, mapper)));
+        assertTrue(types.containsKey("type2".hashCode()));
 
         Map<String, org.apache.ignite.internal.binary.BinaryInternalMapper> typeMappers = U.field(ctx, "cls2Mappers");
 
@@ -387,12 +388,12 @@ public class GridBinaryWildcardsSelfTest extends GridCommonAbstractTest {
 
         BinaryContext ctx = binaryContext(marsh);
 
-        Map<Integer, Class> typeIds = U.field(ctx, "userTypes");
+        ConcurrentMap<Integer, BinaryInternalMapper> types = U.field(ctx, "typeId2Mapper");
 
-        assertEquals(3, typeIds.size());
+        assertEquals(3, types.size());
 
-        assertTrue(typeIds.containsKey(typeId(CLASS1_FULL_NAME, nameMapper, idMapper)));
-        assertTrue(typeIds.containsKey(typeId(CLASS2_FULL_NAME, nameMapper, idMapper)));
+        assertTrue(types.containsKey(typeId(CLASS1_FULL_NAME, nameMapper, idMapper)));
+        assertTrue(types.containsKey(typeId(CLASS2_FULL_NAME, nameMapper, idMapper)));
     }
 
     /**
@@ -460,12 +461,12 @@ public class GridBinaryWildcardsSelfTest extends GridCommonAbstractTest {
 
         BinaryContext ctx = binaryContext(marsh);
 
-        Map<Integer, Class> typeIds = U.field(ctx, "userTypes");
+        ConcurrentMap<Integer, BinaryInternalMapper> types = U.field(ctx, "typeId2Mapper");
 
-        assertEquals(3, typeIds.size());
+        assertEquals(3, types.size());
 
-        assertTrue(typeIds.containsKey(typeId(CLASS1_FULL_NAME, nameMapper, idMapper)));
-        assertTrue(typeIds.containsKey(typeId(CLASS2_FULL_NAME, nameMapper, idMapper)));
+        assertTrue(types.containsKey(typeId(CLASS1_FULL_NAME, nameMapper, idMapper)));
+        assertTrue(types.containsKey(typeId(CLASS2_FULL_NAME, nameMapper, idMapper)));
     }
 
     /**
@@ -580,11 +581,11 @@ public class GridBinaryWildcardsSelfTest extends GridCommonAbstractTest {
 
         BinaryContext ctx = binaryContext(marsh);
 
-        Map<Integer, Class> typeIds = U.field(ctx, "userTypes");
+        ConcurrentMap<Integer, BinaryInternalMapper> types = U.field(ctx, "typeId2Mapper");
 
-        assertEquals(3, typeIds.size());
+        assertEquals(3, types.size());
 
-        assertTrue(typeIds.containsKey(typeId(CLASS1_FULL_NAME, nameMapper, idMapper)));
+        assertTrue(types.containsKey(typeId(CLASS1_FULL_NAME, nameMapper, idMapper)));
 
         Map<String, org.apache.ignite.internal.binary.BinaryInternalMapper> typeMappers = U.field(ctx, "cls2Mappers");
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/binary/GridCacheBinaryObjectUserClassloaderSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/binary/GridCacheBinaryObjectUserClassloaderSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/binary/GridCacheBinaryObjectUserClassloaderSelfTest.java
new file mode 100644
index 0000000..4355796
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/binary/GridCacheBinaryObjectUserClassloaderSelfTest.java
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.internal.processors.cache.binary;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.binary.BinaryReader;
+import org.apache.ignite.binary.BinarySerializer;
+import org.apache.ignite.binary.BinaryTypeConfiguration;
+import org.apache.ignite.binary.BinaryWriter;
+import org.apache.ignite.configuration.BinaryConfiguration;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.binary.BinaryMarshaller;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.cache.CacheMode.REPLICATED;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+
+/**
+ *
+ */
+public class GridCacheBinaryObjectUserClassloaderSelfTest extends GridCommonAbstractTest {
+    /** */
+    private static volatile boolean customBinaryConf = false;
+
+    /** */
+    private static volatile boolean deserialized = false;
+
+    /** */
+    private static volatile boolean useWrappingLoader = false;
+
+    /** */
+    private TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        stopAllGrids();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        TcpDiscoverySpi disco = new TcpDiscoverySpi();
+
+        disco.setIpFinder(ipFinder);
+
+        cfg.setDiscoverySpi(disco);
+
+        cfg.setCacheConfiguration(cacheConfiguration(gridName));
+
+        cfg.setMarshaller(new BinaryMarshaller());
+
+        cfg.setClassLoader(useWrappingLoader ? new WrappingClassLoader(getExternalClassLoader()) :
+            getExternalClassLoader());
+
+        if (customBinaryConf) {
+            BinarySerializer bs = new BinarySerializer() {
+                /** {@inheritDoc} */
+                @Override public void writeBinary(Object obj, BinaryWriter writer) throws BinaryObjectException {
+                    //No-op.
+                }
+
+                /** {@inheritDoc} */
+                @Override public void readBinary(Object obj, BinaryReader reader) throws BinaryObjectException {
+                    deserialized = true;
+                }
+            };
+
+            BinaryTypeConfiguration btcfg1 = new BinaryTypeConfiguration();
+
+            btcfg1.setTypeName("org.apache.ignite.tests.p2p.CacheDeploymentTestValue");
+
+            btcfg1.setSerializer(bs);
+
+            BinaryTypeConfiguration btcfg2 = new BinaryTypeConfiguration();
+
+            btcfg2.setTypeName("org.apache.ignite.internal.processors.cache.binary." +
+                "GridCacheBinaryObjectUserClassloaderSelfTest$TestValue1");
+
+            btcfg2.setSerializer(bs);
+
+            BinaryConfiguration bcfg = new BinaryConfiguration();
+
+            Set<BinaryTypeConfiguration> set = new HashSet<>();
+
+            set.add(btcfg1);
+            set.add(btcfg2);
+
+            bcfg.setTypeConfigurations(set);
+
+            cfg.setBinaryConfiguration(bcfg);
+        }
+
+        return cfg;
+    }
+
+    /**
+     * Gets cache configuration for grid with specified name.
+     *
+     * @param gridName Grid name.
+     * @return Cache configuration.
+     */
+    CacheConfiguration cacheConfiguration(String gridName) {
+        CacheConfiguration cacheCfg = defaultCacheConfiguration();
+
+        cacheCfg.setCacheMode(REPLICATED);
+        cacheCfg.setWriteSynchronizationMode(FULL_SYNC);
+
+        return cacheCfg;
+    }
+
+
+    /**
+     * @throws Exception If test failed.
+     */
+    public void testConfigurationRegistration() throws Exception {
+        useWrappingLoader = false;
+
+        doTestConfigurationRegistration();
+    }
+
+    /**
+     * @throws Exception If test failed.
+     */
+    public void testConfigurationRegistrationWithWrappingLoader() throws Exception {
+        useWrappingLoader = true;
+
+        doTestConfigurationRegistration();
+    }
+
+    /**
+     * @throws Exception If test failed.
+     */
+    private void doTestConfigurationRegistration() throws Exception {
+        try {
+            customBinaryConf = true;
+
+            Ignite i1 = startGrid(1);
+            Ignite i2 = startGrid(2);
+
+            IgniteCache<Integer, Object> cache1 = i1.cache(null);
+            IgniteCache<Integer, Object> cache2 = i2.cache(null);
+
+            ClassLoader ldr = useWrappingLoader ?
+                ((WrappingClassLoader)i1.configuration().getClassLoader()).getParent() :
+                i1.configuration().getClassLoader();
+
+            Object v1 = ldr.loadClass("org.apache.ignite.tests.p2p.CacheDeploymentTestValue").newInstance();
+            Object v2 = ldr.loadClass("org.apache.ignite.tests.p2p.CacheDeploymentTestValue2").newInstance();
+
+            cache1.put(1, v1);
+            cache1.put(2, v2);
+            cache1.put(3, new TestValue1(123));
+            cache1.put(4, new TestValue2(123));
+
+            deserialized = false;
+
+            cache2.get(1);
+
+            assertTrue(deserialized);
+
+            deserialized = false;
+
+            cache2.get(2);
+
+            assertFalse(deserialized);
+
+            deserialized = false;
+
+            cache2.get(3);
+
+            assertTrue(deserialized);
+
+            deserialized = false;
+
+            cache2.get(4);
+
+            assertFalse(deserialized);
+        }
+        finally {
+            customBinaryConf = false;
+        }
+    }
+
+    /**
+     *
+     */
+    private static class TestValue1 implements Serializable {
+        /** */
+        private int val;
+
+        /**
+         * @param val Value.
+         */
+        public TestValue1(int val) {
+            this.val = val;
+        }
+
+        /**
+         * @return Value.
+         */
+        public int value() {
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(TestValue1.class, this);
+        }
+    }
+
+    /**
+     *
+     */
+    private static class TestValue2 implements Serializable {
+        /** */
+        private int val;
+
+        /**
+         * @param val Value.
+         */
+        public TestValue2(int val) {
+            this.val = val;
+        }
+
+        /**
+         * @return Value.
+         */
+        public int value() {
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(TestValue2.class, this);
+        }
+    }
+
+    /**
+     *
+     */
+    private static class WrappingClassLoader extends ClassLoader {
+        public WrappingClassLoader(ClassLoader parent) {
+            super(parent);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/core/src/test/java/org/apache/ignite/marshaller/MarshallerContextTestImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/marshaller/MarshallerContextTestImpl.java b/modules/core/src/test/java/org/apache/ignite/marshaller/MarshallerContextTestImpl.java
index e4921f4..c600ca4 100644
--- a/modules/core/src/test/java/org/apache/ignite/marshaller/MarshallerContextTestImpl.java
+++ b/modules/core/src/test/java/org/apache/ignite/marshaller/MarshallerContextTestImpl.java
@@ -62,4 +62,11 @@ public class MarshallerContextTestImpl extends MarshallerContextAdapter {
     @Override protected String className(int id) {
         return map.get(id);
     }
+
+    /**
+     * @return Internal map.
+     */
+    public ConcurrentMap<Integer, String> internalMap() {
+        return map;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
index 170e9cf..3910ce4 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
@@ -484,7 +484,8 @@ public abstract class GridAbstractTest extends TestCase {
      * @throws Exception If failed. {@link #afterTestsStopped()} will be called in this case.
      */
     protected void beforeTestsStarted() throws Exception {
-        // No-op.
+        // Will clean and re-create marshaller directory from scratch.
+        U.resolveWorkDirectory("marshaller", true);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsTestSuite.java
index 73c22e4..cedf9a7 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsTestSuite.java
@@ -47,6 +47,7 @@ import org.apache.ignite.internal.binary.noncompact.BinaryObjectBuilderNonCompac
 import org.apache.ignite.internal.binary.streams.BinaryHeapStreamByteOrderSelfTest;
 import org.apache.ignite.internal.binary.streams.BinaryOffheapStreamByteOrderSelfTest;
 import org.apache.ignite.internal.processors.cache.BinaryObjectOffHeapUnswapTemporaryTest;
+import org.apache.ignite.internal.processors.cache.binary.GridCacheBinaryObjectUserClassloaderSelfTest;
 import org.apache.ignite.internal.processors.cache.binary.GridCacheBinaryStoreBinariesDefaultMappersSelfTest;
 import org.apache.ignite.internal.processors.cache.binary.GridCacheBinaryStoreBinariesSimpleNameMappersSelfTest;
 import org.apache.ignite.internal.processors.cache.binary.GridCacheBinaryStoreObjectsSelfTest;
@@ -140,6 +141,8 @@ public class IgniteBinaryObjectsTestSuite extends TestSuite {
         suite.addTestSuite(BinaryHeapStreamByteOrderSelfTest.class);
         suite.addTestSuite(BinaryOffheapStreamByteOrderSelfTest.class);
 
+        suite.addTestSuite(GridCacheBinaryObjectUserClassloaderSelfTest.class);
+
         return suite;
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/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 002fa26..ef774af 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
@@ -49,6 +49,7 @@
     <Reference Include="System.configuration" />
     <Reference Include="System.Core" />
     <Reference Include="System.Runtime.Serialization" />
+    <Reference Include="System.ServiceProcess" />
     <Reference Include="System.XML" />
   </ItemGroup>
   <ItemGroup>
@@ -156,6 +157,7 @@
     <Compile Include="Services\ServicesAsyncWrapper.cs" />
     <Compile Include="TestRunner.cs" />
     <Compile Include="TypeResolverTest.cs" />
+    <Compile Include="WindowsServiceTest.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Apache.Ignite.Core\Apache.Ignite.Core.csproj">

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/platforms/dotnet/Apache.Ignite.Core.Tests/WindowsServiceTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/WindowsServiceTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/WindowsServiceTest.cs
new file mode 100644
index 0000000..08d365a
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/WindowsServiceTest.cs
@@ -0,0 +1,124 @@
+/*
+ * 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.IO;
+    using System.Linq;
+    using System.ServiceProcess;
+    using Apache.Ignite.Core.Cluster;
+    using Apache.Ignite.Core.Tests.Process;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests windows service deployment and lifecycle.
+    /// <para />
+    /// NOTE: This fixture requires administrative privileges.
+    /// </summary>
+    public class WindowsServiceTest
+    {
+        /// <summary>
+        /// Test fixture set up.
+        /// </summary>
+        [TestFixtureSetUp]
+        public void TestFixtureSetUp()
+        {
+            StopServiceAndUninstall();
+        }
+
+        /// <summary>
+        /// Test fixture tear down.
+        /// </summary>
+        [TestFixtureTearDown]
+        public void TestFixtureTearDown()
+        {
+            StopServiceAndUninstall();
+        }
+
+        /// <summary>
+        /// Tests that service stops when Ignition stops.
+        /// </summary>
+        [Test]
+        public void TestStopFromJava()
+        {
+            var exePath = typeof(IgniteRunner).Assembly.Location;
+            var springPath = Path.GetFullPath(@"config\compute\compute-grid1.xml");
+
+            IgniteProcess.Start(exePath, string.Empty, args: new[]
+            {
+                "/install",
+                "ForceTestClasspath=true",
+                "-springConfigUrl=" + springPath,
+                "-J-Xms513m",
+                "-J-Xmx555m"
+            }).WaitForExit();
+
+            var service = GetIgniteService();
+            Assert.IsNotNull(service);
+
+            service.Start();  // see IGNITE_HOME\work\log for service instance logs
+            service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));
+
+            using (var ignite = Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration())
+            {
+                SpringConfigUrl = springPath
+            }))
+            {
+                Assert.IsTrue(ignite.WaitTopology(2), "Failed to join with service node");
+
+                // Stop remote node via Java task
+                // Doing so will fail the task execution
+                Assert.Throws<ClusterGroupEmptyException>(() =>
+                    ignite.GetCluster().ForRemotes().GetCompute().ExecuteJavaTask<object>(
+                        "org.apache.ignite.platform.PlatformStopIgniteTask", ignite.Name));
+
+                Assert.IsTrue(ignite.WaitTopology(1), "Failed to stop remote node");
+
+                // Check that service has stopped
+                service.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
+            }
+        }
+
+        /// <summary>
+        /// Stops the service and uninstalls it.
+        /// </summary>
+        private static void StopServiceAndUninstall()
+        {
+            var controller = GetIgniteService();
+
+            if (controller != null)
+            {
+                if (controller.CanStop)
+                    controller.Stop();
+
+                controller.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
+
+                var exePath = typeof(IgniteRunner).Assembly.Location;
+                IgniteProcess.Start(exePath, string.Empty, args: new[] {"/uninstall"}).WaitForExit();
+            }
+        }
+
+        /// <summary>
+        /// Gets the ignite service.
+        /// </summary>
+        private static ServiceController GetIgniteService()
+        {
+            return ServiceController.GetServices().FirstOrDefault(x => x.ServiceName.StartsWith("Apache Ignite.NET"));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
index aee82a7..d64f52c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
@@ -348,7 +348,13 @@ namespace Apache.Ignite.Core.Impl
             UU.IgnitionStop(_proc.Context, Name, cancel);
 
             _cbs.Cleanup();
+        }
 
+        /// <summary>
+        /// Called after node has stopped.
+        /// </summary>
+        internal void AfterNodeStop()
+        {
             foreach (var bean in _lifecycleBeans)
                 bean.OnLifecycleEvent(LifecycleEventType.AfterNodeStop);
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
index 8d810e3..f0e881c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs
@@ -1033,6 +1033,12 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
 
             // Allow context to be collected, which will cause resource cleanup in finalizer.
             _ctx = null;
+
+            // Notify grid
+            var ignite = _ignite;
+
+            if (ignite != null)
+                ignite.AfterNodeStop();
         }
         
         private void Error(void* target, int errType, sbyte* errClsChars, int errClsCharsLen, sbyte* errMsgChars,

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/platforms/dotnet/Apache.Ignite/Apache.Ignite.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite/Apache.Ignite.csproj b/modules/platforms/dotnet/Apache.Ignite/Apache.Ignite.csproj
index 08c14f2..747e1a5 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Apache.Ignite.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite/Apache.Ignite.csproj
@@ -33,6 +33,7 @@
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.Configuration" />
+    <Reference Include="System.Configuration.Install" />
     <Reference Include="System.Core" />
     <Reference Include="System.ServiceProcess" />
     <Reference Include="System.Xml.Linq" />
@@ -51,8 +52,10 @@
     <Compile Include="Service\IgniteService.cs">
       <SubType>Component</SubType>
     </Compile>
-    <Compile Include="Service\NativeMethods.cs" />
     <Compile Include="Service\ServiceDescription.cs" />
+    <Compile Include="Service\IgniteServiceInstaller.cs">
+      <SubType>Component</SubType>
+    </Compile>
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Apache.Ignite.Core\Apache.Ignite.Core.csproj">

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/platforms/dotnet/Apache.Ignite/Config/Configurator.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite/Config/Configurator.cs b/modules/platforms/dotnet/Apache.Ignite/Config/Configurator.cs
index af009e8..c595de1 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Config/Configurator.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Config/Configurator.cs
@@ -62,6 +62,9 @@ namespace Apache.Ignite.Config
         /** Command line argument: Config file name to read config section from. */
         private const string CmdConfigFile = "ConfigFileName";
 
+        /** Hidden command line argument: Force test classpath. */
+        private const string CmdForceTestClasspath = "ForceTestClasspath";
+
         /** <inheritDoc /> */
         public static IgniteConfiguration GetConfiguration(Tuple<string, string>[] args)
         {
@@ -94,6 +97,8 @@ namespace Apache.Ignite.Config
                     jvmOpts.Add(arg.Item2);
                 else if (argIs(CmdAssembly))
                     assemblies.Add(arg.Item2);
+                else if (argIs(CmdForceTestClasspath) && arg.Item2 == "true")
+                    Environment.SetEnvironmentVariable("IGNITE_NATIVE_TEST_CLASSPATH", "true");
             }
 
             if (jvmOpts.Count > 0)

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/platforms/dotnet/Apache.Ignite/Service/IgniteService.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite/Service/IgniteService.cs b/modules/platforms/dotnet/Apache.Ignite/Service/IgniteService.cs
index c64c7bf..4517f71 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Service/IgniteService.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Service/IgniteService.cs
@@ -18,41 +18,42 @@
 namespace Apache.Ignite.Service
 {
     using System;
-    using System.ComponentModel;
+    using System.Collections.Generic;
+    using System.Configuration.Install;
     using System.IO;
     using System.Linq;
     using System.Reflection;
-    using System.Runtime.InteropServices;
     using System.ServiceProcess;
     using System.Text;
     using Apache.Ignite.Core;
     using Apache.Ignite.Core.Common;
+    using Apache.Ignite.Core.Lifecycle;
 
     /// <summary>
     /// Ignite windows service.
     /// </summary>
-    internal class IgniteService : ServiceBase
+    internal class IgniteService : ServiceBase, ILifecycleBean
     {
         /** Service name. */
-        private static readonly string SvcName = "Apache Ignite.NET";
+        public const string SvcName = "Apache Ignite.NET";
 
         /** Service display name. */
-        private static readonly string SvcDisplayName = "Apache Ignite.NET " + 
+        public static readonly string SvcDisplayName = SvcName + " " +
             Assembly.GetExecutingAssembly().GetName().Version.ToString(4);
 
         /** Service description. */
-        private static readonly string SvcDesc = "Apache Ignite.NET Service.";
+        public const string SvcDesc = "Apache Ignite.NET Service.";
 
         /** Current executable name. */
         private static readonly string ExeName =
             new FileInfo(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath).FullName;
 
-        /** Current executable fully qualified name. */
-        private static readonly string FullExeName = Path.GetFileName(FullExeName);
-
         /** Ignite configuration to start with. */
         private readonly IgniteConfiguration _cfg;
 
+        /** Stopping recurse check flag. */
+        private bool _isStopping;
+
         /// <summary>
         /// Constructor.
         /// </summary>
@@ -63,6 +64,13 @@ namespace Apache.Ignite.Service
             ServiceName = SvcName;
 
             _cfg = cfg;
+
+            // Subscribe to lifecycle events
+            var beans = _cfg.LifecycleBeans ?? new List<ILifecycleBean>();
+
+            beans.Add(this);
+
+            _cfg.LifecycleBeans = beans;
         }
 
         /** <inheritDoc /> */
@@ -74,7 +82,8 @@ namespace Apache.Ignite.Service
         /** <inheritDoc /> */
         protected override void OnStop()
         {
-            Ignition.StopAll(true);
+            if (!_isStopping)
+                Ignition.StopAll(true);
         }
 
         /// <summary>
@@ -140,47 +149,15 @@ namespace Apache.Ignite.Service
         private static void Install0(Tuple<string, string>[] args)
         {
             // 1. Prepare arguments.
-            var binPath = new StringBuilder(FullExeName).Append(" ").Append(IgniteRunner.Svc);
+            var argString = new StringBuilder(IgniteRunner.Svc);
 
             foreach (var arg in args)
-                binPath.Append(" ").AppendFormat("-{0}={1}", arg.Item1, arg.Item2);
-
-            // 2. Get SC manager.
-            var scMgr = OpenServiceControlManager();
-
-            // 3. Create service.
-            var svc = NativeMethods.CreateService(
-                scMgr,
-                SvcName,
-                SvcDisplayName,
-                983551, // Access constant. 
-                0x10,   // Service type SERVICE_WIN32_OWN_PROCESS.
-                0x2,    // Start type SERVICE_AUTO_START.
-                0x2,    // Error control SERVICE_ERROR_SEVERE.
-                binPath.ToString(),
-                null,
-                IntPtr.Zero,
-                null,
-                null,   // Use priviliged LocalSystem account.
-                null
-            );
-
-            if (svc == IntPtr.Zero)
-                throw new IgniteException("Failed to create the service.", new Win32Exception());
-
-            // 4. Set description.
-            var desc = new ServiceDescription {desc = Marshal.StringToHGlobalUni(SvcDesc)};
-
-
-            try 
-            {
-                if (!NativeMethods.ChangeServiceConfig2(svc, 1u, ref desc)) 
-                    throw new IgniteException("Failed to set service description.", new Win32Exception());
-            }
-            finally 
-            {
-                Marshal.FreeHGlobal(desc.desc);
-            }
+                argString.Append(" ").AppendFormat("-{0}={1}", arg.Item1, arg.Item2);
+
+            IgniteServiceInstaller.Args = argString.ToString();
+
+            // 2. Install service.
+            ManagedInstallerClass.InstallHelper(new[] { ExeName });
         }
 
         /// <summary>
@@ -188,29 +165,18 @@ namespace Apache.Ignite.Service
         /// </summary>
         private static void Uninstall0()
         {
-            var scMgr = OpenServiceControlManager();
-
-            var svc = NativeMethods.OpenService(scMgr, SvcName, 65536);
-
-            if (svc == IntPtr.Zero)
-                throw new IgniteException("Failed to uninstall the service.", new Win32Exception());
-
-            NativeMethods.DeleteService(svc);
+            ManagedInstallerClass.InstallHelper(new[] { ExeName, "/u" });
         }
 
-        /// <summary>
-        /// Opens SC manager.
-        /// </summary>
-        /// <returns>SC manager pointer.</returns>
-        private static IntPtr OpenServiceControlManager()
+        /** <inheritdoc /> */
+        public void OnLifecycleEvent(LifecycleEventType evt)
         {
-            var ptr = NativeMethods.OpenSCManager(null, null, 983103);
-
-            if (ptr == IntPtr.Zero)
-                throw new IgniteException("Failed to initialize Service Control manager " +
-                                          "(did you run the command as administrator?)", new Win32Exception());
+            if (evt == LifecycleEventType.AfterNodeStop)
+            {
+                _isStopping = true;
 
-            return ptr;
+                Stop();
+            }
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/platforms/dotnet/Apache.Ignite/Service/IgniteServiceInstaller.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite/Service/IgniteServiceInstaller.cs b/modules/platforms/dotnet/Apache.Ignite/Service/IgniteServiceInstaller.cs
new file mode 100644
index 0000000..713e568
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite/Service/IgniteServiceInstaller.cs
@@ -0,0 +1,64 @@
+/*
+ * 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.Service
+{
+    using System.Collections;
+    using System.ComponentModel;
+    using System.Configuration.Install;
+    using System.ServiceProcess;
+
+    /// <summary>
+    /// Service installer for InstallUtil.
+    /// </summary>
+    [RunInstaller(true)]
+    public class IgniteServiceInstaller : Installer
+    {
+        /// <summary>
+        /// Gets or sets the service arguments.
+        /// </summary>
+        public static string Args { get; set; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="IgniteServiceInstaller"/> class.
+        /// </summary>
+        public IgniteServiceInstaller()
+        {
+            Installers.Add(new ServiceInstaller
+            {
+                StartType = ServiceStartMode.Automatic,
+                ServiceName = IgniteService.SvcName,
+                Description = IgniteService.SvcDesc,
+                DisplayName = IgniteService.SvcDisplayName
+            });
+
+            Installers.Add(new ServiceProcessInstaller {Account = ServiceAccount.LocalSystem});
+        }
+
+        /** <inheritdoc /> */
+        protected override void OnBeforeInstall(IDictionary savedState)
+        {
+            if (!string.IsNullOrWhiteSpace(Args))
+            {
+                Context.Parameters["assemblyPath"] =
+                    string.Format("\"{0}\" {1}", Context.Parameters["assemblyPath"], Args);
+            }
+
+            base.OnBeforeInstall(savedState);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b50eb654/modules/platforms/dotnet/Apache.Ignite/Service/NativeMethods.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite/Service/NativeMethods.cs b/modules/platforms/dotnet/Apache.Ignite/Service/NativeMethods.cs
deleted file mode 100644
index 56ab15d..0000000
--- a/modules/platforms/dotnet/Apache.Ignite/Service/NativeMethods.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.Service
-{
-    using System;
-    using System.Runtime.InteropServices;
-
-    /// <summary>
-    /// Native methods.
-    /// </summary>
-    internal class NativeMethods
-    {
-        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
-        public static extern IntPtr OpenSCManager(string machineName, string dbName, int access);
-
-        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
-        public static extern IntPtr CreateService(
-            IntPtr db,
-            string svcName,
-            string displayName,
-            int access,
-            int svcType,
-            int startType,
-            int errControl,
-            string binPath,
-            string loadOrderGrp,
-            IntPtr pTagId,
-            string dependencies,
-            string servicesStartName,
-            string pwd
-            );
-
-        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
-        public static extern IntPtr OpenService(IntPtr db, string svcName, int access);
-
-        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
-        public static extern bool DeleteService(IntPtr svc);
-
-        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
-        public static extern bool ChangeServiceConfig2(IntPtr svc,  uint infoLevel, ref ServiceDescription desc);
-    }
-}
\ No newline at end of file


Mime
View raw message