This is an automated email from the ASF dual-hosted git repository.

namelchev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new cf98eadcb04 IGNITE-23202 Fixed server node fail when node service 
filter class unknown (#11539)
cf98eadcb04 is described below

commit cf98eadcb04e8191ed9b5fb1a51b8bbd2b867ab8
Author: Nikolay <[email protected]>
AuthorDate: Mon Oct 7 18:11:54 2024 +0300

    IGNITE-23202 Fixed server node fail when node service filter class unknown 
(#11539)
    
    Co-authored-by: Nikita Amelchev <[email protected]>
---
 .../processors/service/IgniteServiceProcessor.java | 70 ++++++++++++++++++----
 .../service/LazyServiceConfiguration.java          | 53 +++++++++++++++-
 .../processors/service/PreparedConfigurations.java |  5 +-
 .../service/ServiceDeploymentRequest.java          |  7 +--
 .../internal/processors/service/ServiceInfo.java   | 45 +++++++-------
 ...eploymentClassLoadingDefaultMarshallerTest.java | 65 ++++++++++++++++++++
 .../processors/service/ServiceInfoSelfTest.java    | 26 ++++++--
 7 files changed, 221 insertions(+), 50 deletions(-)

diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
index cd35645ee9b..ad547262b88 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
@@ -397,8 +397,16 @@ public class IgniteServiceProcessor extends 
GridProcessorAdapter implements Igni
 
         ServiceProcessorCommonDiscoveryData clusterData = 
(ServiceProcessorCommonDiscoveryData)data.commonData();
 
-        for (ServiceInfo desc : clusterData.registeredServices())
+        for (ServiceInfo desc : clusterData.registeredServices()) {
+            try {
+                unmarshalNodeFilterIfNeeded(desc.configuration());
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException("Cannot join the cluster.", e);
+            }
+
             registerService(desc);
+        }
     }
 
     /** {@inheritDoc} */
@@ -413,15 +421,27 @@ public class IgniteServiceProcessor extends 
GridProcessorAdapter implements Igni
         ClusterNode node,
         DiscoveryDataBag.JoiningNodeDiscoveryData data
     ) {
-        if (data.joiningNodeData() == null || !ctx.security().enabled())
+        if (data.joiningNodeData() == null)
             return null;
 
         List<ServiceInfo> svcs = 
((ServiceProcessorJoinNodeDiscoveryData)data.joiningNodeData()).services();
 
-        SecurityException err = checkDeployPermissionDuringJoin(node, svcs);
+        if (ctx.security().enabled()) {
+            SecurityException err = checkDeployPermissionDuringJoin(node, 
svcs);
 
-        if (err != null)
-            return new IgniteNodeValidationResult(node.id(), err.getMessage());
+            if (err != null)
+                return new IgniteNodeValidationResult(node.id(), 
err.getMessage());
+        }
+
+        for (ServiceInfo svc : svcs) {
+            try {
+                unmarshalNodeFilterIfNeeded(svc.configuration());
+            }
+            catch (IgniteCheckedException e) {
+                return new IgniteNodeValidationResult(node.id(), "Node join is 
rejected [joiningNodeId=" + node.id() +
+                    ", msg=" + e.getMessage() + ']');
+            }
+        }
 
         return null;
     }
@@ -654,7 +674,7 @@ public class IgniteServiceProcessor extends 
GridProcessorAdapter implements Igni
      */
     private PreparedConfigurations<IgniteUuid> 
prepareServiceConfigurations(Collection<ServiceConfiguration> cfgs,
         IgnitePredicate<ClusterNode> dfltNodeFilter) {
-        List<ServiceConfiguration> cfgsCp = new ArrayList<>(cfgs.size());
+        List<LazyServiceConfiguration> cfgsCp = new ArrayList<>(cfgs.size());
 
         List<GridServiceDeploymentFuture<IgniteUuid>> failedFuts = null;
 
@@ -679,12 +699,14 @@ public class IgniteServiceProcessor extends 
GridProcessorAdapter implements Igni
             if (err == null) {
                 try {
                     byte[] srvcBytes = U.marshal(marsh, cfg.getService());
+                    byte[] nodeFilterBytes = U.marshal(marsh, 
cfg.getNodeFilter());
                     byte[] interceptorsBytes = U.marshal(marsh, 
cfg.getInterceptors());
 
                     String[] knownSvcMdtNames = cfg instanceof 
PlatformServiceConfiguration ?
                         ((PlatformServiceConfiguration)cfg).mtdNames() : null;
 
-                    cfgsCp.add(new LazyServiceConfiguration(cfg, srvcBytes, 
interceptorsBytes).platformMtdNames(knownSvcMdtNames));
+                    cfgsCp.add(new LazyServiceConfiguration(cfg, srvcBytes, 
nodeFilterBytes, interceptorsBytes)
+                        .platformMtdNames(knownSvcMdtNames));
                 }
                 catch (Exception e) {
                     U.error(log, "Failed to marshal service with configured 
marshaller " +
@@ -771,7 +793,7 @@ public class IgniteServiceProcessor extends 
GridProcessorAdapter implements Igni
 
             PreparedConfigurations<IgniteUuid> srvcCfg = 
prepareServiceConfigurations(cfgs, dfltNodeFilter);
 
-            List<ServiceConfiguration> cfgsCp = srvcCfg.cfgs;
+            List<LazyServiceConfiguration> cfgsCp = srvcCfg.cfgs;
 
             List<GridServiceDeploymentFuture<IgniteUuid>> failedFuts = 
srvcCfg.failedFuts;
 
@@ -781,7 +803,7 @@ public class IgniteServiceProcessor extends 
GridProcessorAdapter implements Igni
                 try {
                     Collection<ServiceChangeAbstractRequest> reqs = new 
ArrayList<>();
 
-                    for (ServiceConfiguration cfg : cfgsCp) {
+                    for (LazyServiceConfiguration cfg : cfgsCp) {
                         IgniteUuid srvcId = IgniteUuid.randomUuid();
 
                         GridServiceDeploymentFuture<IgniteUuid> fut = new 
GridServiceDeploymentFuture<>(cfg, srvcId);
@@ -1421,6 +1443,23 @@ public class IgniteServiceProcessor extends 
GridProcessorAdapter implements Igni
         }
     }
 
+    /** @param cfg Lazy service configuration. */
+    private void unmarshalNodeFilterIfNeeded(LazyServiceConfiguration cfg) 
throws IgniteCheckedException {
+        if (cfg.getNodeFilter() != null)
+            return;
+
+        GridDeployment dep = 
ctx.deploy().getDeployment(cfg.serviceClassName());
+
+        ClassLoader clsLdr = U.resolveClassLoader(dep != null ? 
dep.classLoader() : null, ctx.config());
+
+        try {
+            cfg.setNodeFilter(U.unmarshal(marsh, cfg.nodeFilterBytes(), 
clsLdr));
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteCheckedException("Failed to unmarshal class of 
service node filter [cfg=" + cfg + ']', e);
+        }
+    }
+
     /**
      * @param ctxs Contexts to cancel.
      * @param cancelCnt Number of contexts to cancel.
@@ -1712,7 +1751,7 @@ public class IgniteServiceProcessor extends 
GridProcessorAdapter implements Igni
                 }
             }
 
-            for (ServiceConfiguration srvcCfg : prepCfgs.cfgs) {
+            for (LazyServiceConfiguration srvcCfg : prepCfgs.cfgs) {
                 ServiceInfo srvcInfo = new ServiceInfo(ctx.localNodeId(), 
IgniteUuid.randomUuid(), srvcCfg, true);
 
                 srvcInfo.context(ctx);
@@ -1764,11 +1803,20 @@ public class IgniteServiceProcessor extends 
GridProcessorAdapter implements Igni
                         "exists : [" + "srvcId" + reqSrvcId + ", srvcTop=" + 
oldDesc.topologySnapshot() + ']');
                 }
                 else {
-                    ServiceConfiguration cfg = 
((ServiceDeploymentRequest)req).configuration();
+                    LazyServiceConfiguration cfg = 
((ServiceDeploymentRequest)req).configuration();
 
                     if (ctx.security().enabled())
                         err = 
checkPermissions(((ServiceDeploymentRequest)req).configuration().getName(), 
SERVICE_DEPLOY);
 
+                    if (err == null) {
+                        try {
+                            unmarshalNodeFilterIfNeeded(cfg);
+                        }
+                        catch (IgniteCheckedException e) {
+                            err = new IgniteCheckedException("Failed to deploy 
service.", e);
+                        }
+                    }
+
                     if (err == null) {
                         oldDesc = lookupInRegisteredServices(cfg.getName());
 
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfiguration.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfiguration.java
index b7fc099e33a..c5c35b2f1fc 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfiguration.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfiguration.java
@@ -18,12 +18,13 @@
 package org.apache.ignite.internal.processors.service;
 
 import java.util.Arrays;
+import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.util.tostring.GridToStringExclude;
 import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.services.Service;
 import org.apache.ignite.services.ServiceCallInterceptor;
 import org.apache.ignite.services.ServiceConfiguration;
-import org.jetbrains.annotations.Nullable;
 
 /**
  * Lazy service configuration.
@@ -36,6 +37,10 @@ public class LazyServiceConfiguration extends 
ServiceConfiguration {
     @GridToStringExclude
     private transient Service srvc;
 
+    /** Node filter. */
+    @GridToStringExclude
+    private transient IgnitePredicate<ClusterNode> nodeFilter;
+
     /** Service interceptors. */
     @GridToStringExclude
     private transient ServiceCallInterceptor[] interceptors;
@@ -46,6 +51,9 @@ public class LazyServiceConfiguration extends 
ServiceConfiguration {
     /** */
     private byte[] srvcBytes;
 
+    /** */
+    private byte[] nodeFilterBytes;
+
     /** */
     private byte[] interceptorsBytes;
 
@@ -65,7 +73,12 @@ public class LazyServiceConfiguration extends 
ServiceConfiguration {
      * @param srvcBytes Marshalled service.
      * @param interceptorsBytes Marshalled interceptors.
      */
-    public LazyServiceConfiguration(ServiceConfiguration cfg, byte[] 
srvcBytes, @Nullable byte[] interceptorsBytes) {
+    public LazyServiceConfiguration(
+        ServiceConfiguration cfg,
+        byte[] srvcBytes,
+        byte[] nodeFilterBytes,
+        byte[] interceptorsBytes
+    ) {
         assert cfg.getService() != null : cfg;
         assert srvcBytes != null;
 
@@ -75,6 +88,7 @@ public class LazyServiceConfiguration extends 
ServiceConfiguration {
         cacheName = cfg.getCacheName();
         affKey = cfg.getAffinityKey();
         nodeFilter = cfg.getNodeFilter();
+        this.nodeFilterBytes = nodeFilterBytes;
         this.srvcBytes = srvcBytes;
         srvc = cfg.getService();
         srvcClsName = srvc.getClass().getName();
@@ -83,6 +97,13 @@ public class LazyServiceConfiguration extends 
ServiceConfiguration {
         this.interceptorsBytes = interceptorsBytes;
     }
 
+    /**
+     * @return Node filter bytes.
+     */
+    public byte[] nodeFilterBytes() {
+        return nodeFilterBytes;
+    }
+
     /**
      * @return Service bytes.
      */
@@ -104,6 +125,18 @@ public class LazyServiceConfiguration extends 
ServiceConfiguration {
         return srvc;
     }
 
+    /** {@inheritDoc} */
+    @Override public ServiceConfiguration 
setNodeFilter(IgnitePredicate<ClusterNode> nodeFilter) {
+        this.nodeFilter = nodeFilter;
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public IgnitePredicate<ClusterNode> getNodeFilter() {
+        return nodeFilter;
+    }
+
     /** {@inheritDoc} */
     @Override public ServiceCallInterceptor[] getInterceptors() {
         return interceptors;
@@ -116,6 +149,19 @@ public class LazyServiceConfiguration extends 
ServiceConfiguration {
         return interceptorsBytes;
     }
 
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (!(o instanceof LazyServiceConfiguration))
+            return super.equals(o);
+
+        if (!equalsIgnoreNodeFilter(o))
+            return false;
+
+        LazyServiceConfiguration that = (LazyServiceConfiguration)o;
+
+        return Arrays.equals(nodeFilterBytes, that.nodeFilterBytes);
+    }
+
     /** {@inheritDoc} */
     @SuppressWarnings("RedundantIfStatement")
     @Override public boolean equalsIgnoreNodeFilter(Object o) {
@@ -168,6 +214,7 @@ public class LazyServiceConfiguration extends 
ServiceConfiguration {
         String svcCls = srvc == null ? "" : srvc.getClass().getSimpleName();
         String nodeFilterCls = nodeFilter == null ? "" : 
nodeFilter.getClass().getSimpleName();
 
-        return S.toString(LazyServiceConfiguration.class, this, "svcCls", 
svcCls, "nodeFilterCls", nodeFilterCls);
+        return S.toString(LazyServiceConfiguration.class, this, "name", name, 
"svcCls", svcCls,
+            "nodeFilterCls", nodeFilterCls);
     }
 }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/PreparedConfigurations.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/PreparedConfigurations.java
index abfb65cb2df..ce20378132e 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/PreparedConfigurations.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/PreparedConfigurations.java
@@ -20,14 +20,13 @@ package org.apache.ignite.internal.processors.service;
 import java.io.Serializable;
 import java.util.List;
 import org.apache.ignite.internal.util.typedef.internal.S;
-import org.apache.ignite.services.ServiceConfiguration;
 
 /**
  * Result of services validation before deployment.
  */
 class PreparedConfigurations<T extends Serializable> {
     /** */
-    final List<ServiceConfiguration> cfgs;
+    final List<LazyServiceConfiguration> cfgs;
 
     /** */
     final List<GridServiceDeploymentFuture<T>> failedFuts;
@@ -36,7 +35,7 @@ class PreparedConfigurations<T extends Serializable> {
      * @param cfgs Configurations to deploy.
      * @param failedFuts Finished futures for failed configurations.
      */
-    PreparedConfigurations(List<ServiceConfiguration> cfgs, 
List<GridServiceDeploymentFuture<T>> failedFuts) {
+    PreparedConfigurations(List<LazyServiceConfiguration> cfgs, 
List<GridServiceDeploymentFuture<T>> failedFuts) {
         this.cfgs = cfgs;
         this.failedFuts = failedFuts;
     }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDeploymentRequest.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDeploymentRequest.java
index d41e5aab7f4..ba7152ed187 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDeploymentRequest.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDeploymentRequest.java
@@ -19,7 +19,6 @@ package org.apache.ignite.internal.processors.service;
 
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.lang.IgniteUuid;
-import org.apache.ignite.services.ServiceConfiguration;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -30,13 +29,13 @@ public class ServiceDeploymentRequest extends 
ServiceChangeAbstractRequest {
     private static final long serialVersionUID = 0L;
 
     /** Service configuration. */
-    private final ServiceConfiguration cfg;
+    private final LazyServiceConfiguration cfg;
 
     /**
      * @param srvcId Service id.
      * @param cfg Service configuration.
      */
-    public ServiceDeploymentRequest(@NotNull IgniteUuid srvcId, @NotNull 
ServiceConfiguration cfg) {
+    public ServiceDeploymentRequest(@NotNull IgniteUuid srvcId, @NotNull 
LazyServiceConfiguration cfg) {
         super(srvcId);
 
         this.cfg = cfg;
@@ -45,7 +44,7 @@ public class ServiceDeploymentRequest extends 
ServiceChangeAbstractRequest {
     /**
      * @return Service configuration.
      */
-    public ServiceConfiguration configuration() {
+    public LazyServiceConfiguration configuration() {
         return cfg;
     }
 
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceInfo.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceInfo.java
index 3d6d60965ff..1d750d13e11 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceInfo.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceInfo.java
@@ -27,7 +27,6 @@ import 
org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.lang.IgniteUuid;
 import org.apache.ignite.services.Service;
-import org.apache.ignite.services.ServiceConfiguration;
 import org.apache.ignite.services.ServiceDescriptor;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -49,7 +48,7 @@ public class ServiceInfo implements ServiceDescriptor {
     private final IgniteUuid srvcId;
 
     /** Service configuration. */
-    private final ServiceConfiguration cfg;
+    private final LazyServiceConfiguration cfg;
 
     /** Statically configured flag. */
     private final boolean staticCfg;
@@ -66,7 +65,7 @@ public class ServiceInfo implements ServiceDescriptor {
      * @param srvcId Service id.
      * @param cfg Service configuration.
      */
-    public ServiceInfo(@NotNull UUID originNodeId, @NotNull IgniteUuid srvcId, 
@NotNull ServiceConfiguration cfg) {
+    public ServiceInfo(@NotNull UUID originNodeId, @NotNull IgniteUuid srvcId, 
@NotNull LazyServiceConfiguration cfg) {
         this(originNodeId, srvcId, cfg, false);
     }
 
@@ -76,7 +75,7 @@ public class ServiceInfo implements ServiceDescriptor {
      * @param cfg Service configuration.
      * @param staticCfg Statically configured flag.
      */
-    public ServiceInfo(@NotNull UUID originNodeId, @NotNull IgniteUuid srvcId, 
@NotNull ServiceConfiguration cfg,
+    public ServiceInfo(@NotNull UUID originNodeId, @NotNull IgniteUuid srvcId, 
@NotNull LazyServiceConfiguration cfg,
         boolean staticCfg) {
         this.originNodeId = originNodeId;
         this.srvcId = srvcId;
@@ -107,7 +106,7 @@ public class ServiceInfo implements ServiceDescriptor {
      *
      * @return Service configuration.
      */
-    public ServiceConfiguration configuration() {
+    public LazyServiceConfiguration configuration() {
         return cfg;
     }
 
@@ -134,34 +133,30 @@ public class ServiceInfo implements ServiceDescriptor {
 
     /** {@inheritDoc} */
     @Override public Class<? extends Service> serviceClass() {
-        if (cfg instanceof LazyServiceConfiguration) {
-            if (srvcCls != null)
-                return srvcCls;
+        if (srvcCls != null)
+            return srvcCls;
 
-            String clsName = 
((LazyServiceConfiguration)cfg).serviceClassName();
+        String clsName = cfg.serviceClassName();
 
-            try {
-                srvcCls = (Class<? extends Service>)Class.forName(clsName);
+        try {
+            srvcCls = (Class<? extends Service>)Class.forName(clsName);
 
-                return srvcCls;
-            }
-            catch (ClassNotFoundException e) {
-                if (ctx != null) {
-                    GridDeployment srvcDep = 
ctx.deploy().getDeployment(clsName);
+            return srvcCls;
+        }
+        catch (ClassNotFoundException e) {
+            if (ctx != null) {
+                GridDeployment srvcDep = ctx.deploy().getDeployment(clsName);
 
-                    if (srvcDep != null) {
-                        srvcCls = (Class<? extends 
Service>)srvcDep.deployedClass(clsName).get1();
+                if (srvcDep != null) {
+                    srvcCls = (Class<? extends 
Service>)srvcDep.deployedClass(clsName).get1();
 
-                        if (srvcCls != null)
-                            return srvcCls;
-                    }
+                    if (srvcCls != null)
+                        return srvcCls;
                 }
-
-                throw new IgniteException("Failed to find service class: " + 
clsName, e);
             }
+
+            throw new IgniteException("Failed to find service class: " + 
clsName, e);
         }
-        else
-            return cfg.getService().getClass();
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingDefaultMarshallerTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingDefaultMarshallerTest.java
index 5ea781ac3d1..febac2431fe 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingDefaultMarshallerTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingDefaultMarshallerTest.java
@@ -19,15 +19,22 @@ package org.apache.ignite.internal.processors.service;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.UUID;
+import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.StopNodeFailureHandler;
+import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.marshaller.Marshaller;
 import org.apache.ignite.services.Service;
 import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.services.ServiceDeploymentException;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
+import static 
org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause;
+
 /**
  * Tests that not all nodes in cluster need user's service definition (only 
nodes according to filter).
  */
@@ -35,6 +42,9 @@ public class 
IgniteServiceDeploymentClassLoadingDefaultMarshallerTest extends Gr
     /** */
     private static final String NOOP_SERVICE_CLS_NAME = 
"org.apache.ignite.tests.p2p.NoopService";
 
+    /** */
+    private static final String NODE_FILTER_CLS_NAME = 
"org.apache.ignite.tests.p2p.ExcludeNodeFilter";
+
     /** */
     private static final int SERVER_NODE = 0;
 
@@ -69,6 +79,8 @@ public class 
IgniteServiceDeploymentClassLoadingDefaultMarshallerTest extends Gr
         if (extClsLdrGrids.contains(igniteInstanceName))
             cfg.setClassLoader(extClsLdr);
 
+        cfg.setFailureHandler(new StopNodeFailureHandler());
+
         return cfg;
     }
 
@@ -152,6 +164,59 @@ public class 
IgniteServiceDeploymentClassLoadingDefaultMarshallerTest extends Gr
         
startClientGrid(CLIENT_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig());
     }
 
+    /** @throws Exception If failed. */
+    @Test
+    public void testFailWhenNodeFilterClassNotFound() throws Exception {
+        IgniteEx srv = startGrid(SERVER_NODE);
+        IgniteEx cli = startClientGrid(CLIENT_NODE);
+
+        ServiceConfiguration svcCfg = new ServiceConfiguration()
+            .setName("TestDeploymentService")
+            
.setService(((Class<Service>)extClsLdr.loadClass(NOOP_SERVICE_CLS_NAME)).getDeclaredConstructor().newInstance())
+            
.setNodeFilter(((Class<IgnitePredicate<ClusterNode>>)extClsLdr.loadClass(NODE_FILTER_CLS_NAME))
+                .getConstructor(UUID.class)
+                .newInstance(cli.context().localNodeId()))
+            .setTotalCount(1);
+
+        // 1. Node filter class not found on nodes.
+        assertThrowsWithCause(() -> cli.services().deploy(svcCfg), 
ServiceDeploymentException.class);
+
+        // 2. Node filter class not found on cluster nodes during node join.
+        IgniteConfiguration cfg = 
getConfiguration(getTestIgniteInstanceName(SERVER_NODE_WITH_EXT_CLASS_LOADER))
+            .setServiceConfiguration(svcCfg);
+
+        assertThrowsWithCause(() -> startGrid(cfg), 
IgniteCheckedException.class);
+
+        assertTrue(cli.services().serviceDescriptors().isEmpty());
+        assertTrue(srv.services().serviceDescriptors().isEmpty());
+
+        // Check node availability.
+        srv.createCache(DEFAULT_CACHE_NAME).put(1, 1);
+        cli.cache(DEFAULT_CACHE_NAME).put(2, 2);
+    }
+
+    /** @throws Exception If failed. */
+    @Test
+    public void testFailWhenNodeFilterClassNotFoundOnJoiningNode() throws 
Exception {
+        IgniteEx srv = startGrid(SERVER_NODE_WITH_EXT_CLASS_LOADER);
+        IgniteEx cli = startClientGrid(CLIENT_NODE_WITH_EXT_CLASS_LOADER);
+
+        ServiceConfiguration svcCfg = new ServiceConfiguration()
+            .setName("TestDeploymentService")
+            
.setService(((Class<Service>)extClsLdr.loadClass(NOOP_SERVICE_CLS_NAME)).getDeclaredConstructor().newInstance())
+            
.setNodeFilter(((Class<IgnitePredicate<ClusterNode>>)extClsLdr.loadClass(NODE_FILTER_CLS_NAME))
+                .getConstructor(UUID.class)
+                .newInstance(cli.context().localNodeId()))
+            .setTotalCount(1);
+
+        cli.services().deploy(svcCfg);
+
+        assertThrowsWithCause(() -> startGrid(SERVER_NODE), 
IgniteCheckedException.class);
+
+        assertEquals(1, cli.services().serviceDescriptors().size());
+        assertEquals(1, srv.services().serviceDescriptors().size());
+    }
+
     /**
      * @return Service configuration.
      * @throws Exception If failed.
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/ServiceInfoSelfTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/ServiceInfoSelfTest.java
index 6233168a6e7..60b9531d45e 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/ServiceInfoSelfTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/ServiceInfoSelfTest.java
@@ -23,8 +23,11 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.util.HashMap;
 import java.util.UUID;
+import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.marshaller.jdk.JdkMarshaller;
 import org.apache.ignite.services.Service;
 import org.apache.ignite.services.ServiceConfiguration;
 import org.apache.ignite.services.ServiceContext;
@@ -32,7 +35,6 @@ import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertSame;
 
 /**
  * Tests of {@link ServiceInfo} class.
@@ -48,15 +50,13 @@ public class ServiceInfoSelfTest {
     private ServiceConfiguration cfg = configuration();
 
     /** Subject under test. */
-    private ServiceInfo sut = new ServiceInfo(nodeId, srvcId, cfg);
+    private ServiceInfo sut = serviceInfo(cfg);
 
     /**
      * Tests {@link ServiceInfo#configuration()}.
      */
     @Test
     public void testConfigurationEquality() {
-        assertSame(cfg, sut.configuration());
-
         assertEquals(cfg.getService().getClass(), sut.serviceClass());
 
         assertEquals(cfg.getName(), sut.name());
@@ -138,6 +138,24 @@ public class ServiceInfoSelfTest {
         return cfg;
     }
 
+    /** */
+    private ServiceInfo serviceInfo(ServiceConfiguration cfg) {
+        try {
+            JdkMarshaller marsh = new JdkMarshaller();
+
+            byte[] srvcBytes = U.marshal(marsh, cfg.getService());
+            byte[] nodeFilterBytes = U.marshal(marsh, cfg.getNodeFilter());
+            byte[] interceptorsBytes = U.marshal(marsh, cfg.getInterceptors());
+
+            LazyServiceConfiguration lazyCfg = new 
LazyServiceConfiguration(cfg, srvcBytes, nodeFilterBytes, interceptorsBytes);
+
+            return new ServiceInfo(nodeId, srvcId, lazyCfg);
+        }
+        catch (IgniteCheckedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     /**
      * Tests service implementation.
      */

Reply via email to