ignite-3056: Service implementation class is required even if it's not expected 
to be deployed on current node (fixed)


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

Branch: refs/heads/ignite-3163
Commit: bab0533d9b3e21759f44db1538bd5a3c7071db5a
Parents: 3d6e179
Author: ashutak <[email protected]>
Authored: Wed May 18 13:27:02 2016 +0300
Committer: ashutak <[email protected]>
Committed: Wed May 18 14:01:55 2016 +0300

----------------------------------------------------------------------
 .../apache/ignite/IgniteSystemProperties.java   |  15 ++
 .../ignite/internal/IgniteNodeAttributes.java   |   3 +
 .../discovery/GridDiscoveryManager.java         |  31 +++
 .../service/GridServiceAssignments.java         |  10 +-
 .../service/GridServiceProcessor.java           | 215 ++++++++++++++-
 .../service/LazyServiceConfiguration.java       | 129 +++++++++
 .../service/ServiceDescriptorImpl.java          |  17 +-
 .../ignite/services/ServiceConfiguration.java   |  14 +-
 .../ignite/spi/discovery/tcp/ServerImpl.java    |  72 ++++++
 .../GridDiscoveryManagerAttributesSelfTest.java |  63 +++++
 ...yment2ClassLoadersDefaultMarshallerTest.java | 259 +++++++++++++++++++
 ...eployment2ClassLoadersJdkMarshallerTest.java |  31 +++
 ...ent2ClassLoadersOptimizedMarshallerTest.java |  31 +++
 ...oymentClassLoadingDefaultMarshallerTest.java | 212 +++++++++++++++
 ...DeploymentClassLoadingJdkMarshallerTest.java |  31 +++
 ...mentClassLoadingOptimizedMarshallerTest.java |  31 +++
 .../testsuites/IgniteKernalSelfTestSuite.java   |  13 +
 .../apache/ignite/tests/p2p/NoopService.java    |  41 +++
 .../apache/ignite/tests/p2p/NoopService2.java   |  41 +++
 19 files changed, 1229 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java 
b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
index db1d093..50d60e8 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
@@ -429,6 +429,21 @@ public final class IgniteSystemProperties {
         "IGNITE_H2_INDEXING_CACHE_THREAD_USAGE_TIMEOUT";
 
     /**
+     * Manages backward compatibility of {@link IgniteServices}. All nodes in 
cluster must have identical value
+     * of this property.
+     * <p>
+     * If property is {@code false} then node is not required to have service 
implementation class if service is not
+     * deployed on this node.
+     * <p>
+     * If the property is {@code true} then service implementation class is 
required on node even if service
+     * is not deployed on this node.
+     * <p>
+     * If the property is not set ({@code null}) then Ignite will 
automatically detect which compatibility mode
+     * should be used.
+     */
+    public static final String IGNITE_SERVICES_COMPATIBILITY_MODE = 
"IGNITE_SERVICES_COMPATIBILITY_MODE";
+
+    /**
      * Enforces singleton.
      */
     private IgniteSystemProperties() {

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
index 744439c..3425793 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
@@ -154,6 +154,9 @@ public final class IgniteNodeAttributes {
     /** Binary configuration. */
     public static final String ATTR_BINARY_CONFIGURATION = ATTR_PREFIX + 
".binary.config";
 
+    /** Ignite services compatibility mode (can be {@code null}). */
+    public static final String ATTR_SERVICES_COMPATIBILITY_MODE = ATTR_PREFIX 
+ ".services.compatibility.enabled";
+
     /**
      * Enforces singleton.
      */

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
index 2779d6f..180904e 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
@@ -78,6 +78,7 @@ import 
org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
 import org.apache.ignite.internal.processors.jobmetrics.GridJobMetrics;
 import org.apache.ignite.internal.processors.security.SecurityContext;
+import org.apache.ignite.internal.processors.service.GridServiceProcessor;
 import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor;
 import org.apache.ignite.internal.util.F0;
 import org.apache.ignite.internal.util.GridBoundedConcurrentOrderedMap;
@@ -119,6 +120,7 @@ import org.jsr166.ConcurrentHashMap8;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_OPTIMIZED_MARSHALLER_USE_DEFAULT_SUID;
+import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICES_COMPATIBILITY_MODE;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_BINARY_MARSHALLER_USE_STRING_SERIALIZATION_VER_2;
 import static org.apache.ignite.events.EventType.EVT_CLIENT_NODE_DISCONNECTED;
 import static org.apache.ignite.events.EventType.EVT_CLIENT_NODE_RECONNECTED;
@@ -128,10 +130,12 @@ import static 
org.apache.ignite.events.EventType.EVT_NODE_LEFT;
 import static org.apache.ignite.events.EventType.EVT_NODE_METRICS_UPDATED;
 import static org.apache.ignite.events.EventType.EVT_NODE_SEGMENTED;
 import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_DEPLOYMENT_MODE;
+import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_LATE_AFFINITY_ASSIGNMENT;
 import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MACS;
 import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_USE_BINARY_STRING_SER_VER_2;
 import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_USE_DFLT_SUID;
 import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_PEER_CLASSLOADING;
+import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SERVICES_COMPATIBILITY_MODE;
 import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_USER_NAME;
 import static org.apache.ignite.internal.IgniteVersionUtils.VER;
 import static org.apache.ignite.plugin.segmentation.SegmentationPolicy.NOOP;
@@ -691,6 +695,8 @@ public class GridDiscoveryManager extends 
GridManagerAdapter<DiscoverySpi> {
 
         checkAttributes(discoCache().remoteNodes());
 
+        ctx.service().initCompatibilityMode(discoCache().remoteNodes());
+
         // Start discovery worker.
         new IgniteThread(discoWrk).start();
 
@@ -1006,6 +1012,8 @@ public class GridDiscoveryManager extends 
GridManagerAdapter<DiscoverySpi> {
             false /* turned on and added to the attributes list by default 
only when BinaryMarshaller is used. */ :
             locMarshStrSerVer2;
 
+        Boolean locSrvcCompatibilityEnabled = 
locNode.attribute(ATTR_SERVICES_COMPATIBILITY_MODE);
+
         for (ClusterNode n : nodes) {
             int rmtJvmMajVer = nodeJavaMajorVersion(n);
 
@@ -1079,6 +1087,29 @@ public class GridDiscoveryManager extends 
GridManagerAdapter<DiscoverySpi> {
                     ", locNodeId=" + locNode.id() + ", rmtNodeId=" + n.id() + 
']');
             }
 
+            if 
(n.version().compareToIgnoreTimestamp(GridServiceProcessor.LAZY_SERVICES_CFG_SINCE)
 >= 0) {
+                Boolean rmtSrvcCompatibilityEnabled = 
n.attribute(ATTR_SERVICES_COMPATIBILITY_MODE);
+
+                if (!F.eq(locSrvcCompatibilityEnabled, 
rmtSrvcCompatibilityEnabled)) {
+                    throw new IgniteCheckedException("Local node's " + 
IGNITE_SERVICES_COMPATIBILITY_MODE +
+                        " property value differs from remote node's value " +
+                        "(to make sure all nodes in topology have identical 
IgniteServices compatibility mode enabled, " +
+                        "configure system property explicitly) " +
+                        "[locSrvcCompatibilityEnabled=" + 
locSrvcCompatibilityEnabled +
+                        ", rmtSrvcCompatibilityEnabled=" + 
rmtSrvcCompatibilityEnabled +
+                        ", locNodeAddrs=" + U.addressesAsString(locNode) +
+                        ", rmtNodeAddrs=" + U.addressesAsString(n) +
+                        ", locNodeId=" + locNode.id() + ", rmtNodeId=" + 
n.id() + ']');
+                }
+            }
+            else if (Boolean.FALSE.equals(locSrvcCompatibilityEnabled)) {
+                throw new IgniteCheckedException("Remote node doesn't support 
lazy services configuration and " +
+                    "local node cannot join node because local node's "
+                    + IGNITE_SERVICES_COMPATIBILITY_MODE + " property value 
explicitly set to 'false'" +
+                    "[locNodeAddrs=" + U.addressesAsString(locNode) +
+                    ", rmtNodeAddrs=" + U.addressesAsString(n) +
+                    ", locNodeId=" + locNode.id() + ", rmtNodeId=" + n.id() + 
']');
+            }
         }
 
         if (log.isDebugEnabled())

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceAssignments.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceAssignments.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceAssignments.java
index c629a48..66b2816 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceAssignments.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceAssignments.java
@@ -26,7 +26,6 @@ import 
org.apache.ignite.internal.processors.cache.GridCacheInternal;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 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.ServiceConfiguration;
 
 /**
@@ -75,13 +74,6 @@ public class GridServiceAssignments implements Serializable, 
GridCacheInternal {
     }
 
     /**
-     * @return Service.
-     */
-    public Service service() {
-        return cfg.getService();
-    }
-
-    /**
      * @return Topology version.
      */
     public long topologyVersion() {
@@ -134,4 +126,4 @@ public class GridServiceAssignments implements 
Serializable, GridCacheInternal {
     @Override public String toString() {
         return S.toString(GridServiceAssignments.class, this);
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java
index b5634e9..97d9988 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java
@@ -32,6 +32,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
 import javax.cache.Cache;
 import javax.cache.event.CacheEntryEvent;
 import javax.cache.event.CacheEntryListenerException;
@@ -84,13 +85,17 @@ import org.apache.ignite.resources.IgniteInstanceResource;
 import org.apache.ignite.services.Service;
 import org.apache.ignite.services.ServiceConfiguration;
 import org.apache.ignite.services.ServiceDescriptor;
+import org.apache.ignite.spi.IgniteNodeValidationResult;
 import org.apache.ignite.thread.IgniteThreadFactory;
 import org.jetbrains.annotations.Nullable;
 import org.jsr166.ConcurrentHashMap8;
 
+import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICES_COMPATIBILITY_MODE;
+import static org.apache.ignite.IgniteSystemProperties.getString;
 import static org.apache.ignite.configuration.DeploymentMode.ISOLATED;
 import static org.apache.ignite.configuration.DeploymentMode.PRIVATE;
 import static org.apache.ignite.events.EventType.EVTS_DISCOVERY;
+import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SERVICES_COMPATIBILITY_MODE;
 import static 
org.apache.ignite.internal.processors.cache.GridCacheUtils.UTILITY_CACHE_NAME;
 import static 
org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
 import static 
org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
@@ -100,9 +105,18 @@ import static 
org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_REA
  */
 @SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter", 
"ConstantConditions"})
 public class GridServiceProcessor extends GridProcessorAdapter {
+    /** */
+    public static final IgniteProductVersion LAZY_SERVICES_CFG_SINCE = 
IgniteProductVersion.fromString("1.5.22");
+
+    /** */
+    private final Boolean srvcCompatibilitySysProp;
+
     /** Time to wait before reassignment retries. */
     private static final long RETRY_TIMEOUT = 1000;
 
+    /** */
+    private final AtomicReference<ServicesCompatibilityState> 
compatibilityState;
+
     /** Local service instances. */
     private final Map<String, Collection<ServiceContextImpl>> locSvcs = new 
HashMap<>();
 
@@ -143,10 +157,19 @@ public class GridServiceProcessor extends 
GridProcessorAdapter {
         super(ctx);
 
         depExe = Executors.newSingleThreadExecutor(new 
IgniteThreadFactory(ctx.gridName(), "srvc-deploy"));
+
+        String servicesCompatibilityMode = 
getString(IGNITE_SERVICES_COMPATIBILITY_MODE);
+
+        srvcCompatibilitySysProp = servicesCompatibilityMode == null ? null : 
Boolean.valueOf(servicesCompatibilityMode);
+
+        compatibilityState = new AtomicReference<>(
+            new ServicesCompatibilityState(srvcCompatibilitySysProp != null ? 
srvcCompatibilitySysProp : false, false));
     }
 
     /** {@inheritDoc} */
     @Override public void start() throws IgniteCheckedException {
+        ctx.addNodeAttribute(ATTR_SERVICES_COMPATIBILITY_MODE, 
srvcCompatibilitySysProp);
+
         if (ctx.isDaemon())
             return;
 
@@ -390,8 +413,30 @@ public class GridServiceProcessor extends 
GridProcessorAdapter {
     public IgniteInternalFuture<?> deploy(ServiceConfiguration cfg) {
         A.notNull(cfg, "cfg");
 
+        ServicesCompatibilityState state = markCompatibilityStateAsUsed();
+
         validate(cfg);
 
+        if (!state.srvcCompatibility) {
+            Marshaller marsh = ctx.config().getMarshaller();
+
+            LazyServiceConfiguration cfg0;
+
+            try {
+                byte[] srvcBytes = marsh.marshal(cfg.getService());
+
+                cfg0 = new LazyServiceConfiguration(cfg, srvcBytes);
+            }
+            catch (IgniteCheckedException e) {
+                U.error(log, "Failed to marshal service with configured 
marshaller [srvc=" + cfg.getService()
+                    + ", marsh=" + marsh + "]", e);
+
+                return new GridFinishedFuture<>(e);
+            }
+
+            cfg = cfg0;
+        }
+
         GridServiceDeploymentFuture fut = new GridServiceDeploymentFuture(cfg);
 
         GridServiceDeploymentFuture old = depFuts.putIfAbsent(cfg.getName(), 
fut);
@@ -487,6 +532,23 @@ public class GridServiceProcessor extends 
GridProcessorAdapter {
     }
 
     /**
+     * @return Compatibility state.
+     */
+    private ServicesCompatibilityState markCompatibilityStateAsUsed() {
+        while (true) {
+            ServicesCompatibilityState state = compatibilityState.get();
+
+            if (state.used)
+                return state;
+
+            ServicesCompatibilityState newState = new 
ServicesCompatibilityState(state.srvcCompatibility, true);
+
+            if (compatibilityState.compareAndSet(state, newState))
+                return newState;
+        }
+    }
+
+    /**
      * @param name Service name.
      * @return Future.
      */
@@ -950,16 +1012,18 @@ public class GridServiceProcessor extends 
GridProcessorAdapter {
         }
 
         for (final ServiceContextImpl svcCtx : toInit) {
-            final Service svc = copyAndInject(assigns.service());
+            final Service svc;
 
             try {
+                svc = copyAndInject(assigns.configuration());
+
                 // Initialize service.
                 svc.init(svcCtx);
 
                 svcCtx.service(svc);
             }
             catch (Throwable e) {
-                log.error("Failed to initialize service (service will not be 
deployed): " + assigns.name(), e);
+                U.error(log, "Failed to initialize service (service will not 
be deployed): " + assigns.name(), e);
 
                 synchronized (ctxs) {
                     ctxs.removeAll(toInit);
@@ -1020,26 +1084,40 @@ public class GridServiceProcessor extends 
GridProcessorAdapter {
     }
 
     /**
-     * @param svc Service.
+     * @param cfg Service configuration.
      * @return Copy of service.
+     * @throws IgniteCheckedException If failed.
      */
-    private Service copyAndInject(Service svc) {
+    private Service copyAndInject(ServiceConfiguration cfg) throws 
IgniteCheckedException {
         Marshaller m = ctx.config().getMarshaller();
 
-        try {
-            byte[] bytes = m.marshal(svc);
+        if (cfg instanceof LazyServiceConfiguration) {
+            byte[] bytes = ((LazyServiceConfiguration)cfg).serviceBytes();
 
-            Service cp = m.unmarshal(bytes,
-                U.resolveClassLoader(svc.getClass().getClassLoader(), 
ctx.config()));
+            Service srvc = m.unmarshal(bytes, U.resolveClassLoader(null, 
ctx.config()));
 
-            ctx.resource().inject(cp);
+            ctx.resource().inject(srvc);
 
-            return cp;
+            return srvc;
         }
-        catch (IgniteCheckedException e) {
-            log.error("Failed to copy service (will reuse same instance): " + 
svc.getClass(), e);
+        else {
+            Service svc = cfg.getService();
+
+            try {
+                byte[] bytes = m.marshal(svc);
+
+                Service cp = m.unmarshal(bytes,
+                    U.resolveClassLoader(svc.getClass().getClassLoader(), 
ctx.config()));
+
+                ctx.resource().inject(cp);
 
-            return svc;
+                return cp;
+            }
+            catch (IgniteCheckedException e) {
+                U.error(log, "Failed to copy service (will reuse same 
instance): " + svc.getClass(), e);
+
+                return svc;
+            }
         }
     }
 
@@ -1136,6 +1214,73 @@ public class GridServiceProcessor extends 
GridProcessorAdapter {
         }
     }
 
+    /** {@inheritDoc} */
+    @Nullable @Override public IgniteNodeValidationResult 
validateNode(ClusterNode node) {
+        IgniteNodeValidationResult res = super.validateNode(node);
+
+        if (res != null)
+            return res;
+
+        boolean rmtNodeIsOld = 
node.version().compareToIgnoreTimestamp(LAZY_SERVICES_CFG_SINCE) < 0;
+
+        if (!rmtNodeIsOld)
+            return null;
+
+        while (true) {
+            ServicesCompatibilityState state = compatibilityState.get();
+
+            if (state.srvcCompatibility)
+                return null;
+
+            // Remote node is old and services are in not compatible mode.
+            if (!state.used) {
+                if (!compatibilityState.compareAndSet(state, new 
ServicesCompatibilityState(true, false)))
+                    continue;
+
+                return null;
+            }
+
+            ClusterNode locNode = ctx.discovery().localNode();
+
+            return new IgniteNodeValidationResult(node.id(), "Local node uses 
IgniteServices and works in not " +
+                "compatible mode with old nodes (" + 
IGNITE_SERVICES_COMPATIBILITY_MODE + " system property can be " +
+                "set explicitly) [locNodeId=" + locNode.id() + ", rmtNodeId=" 
+ node.id() + "]",
+                "Remote node uses IgniteServices and works in not compatible 
mode with old nodes " +
+                    IGNITE_SERVICES_COMPATIBILITY_MODE + " system property can 
be set explicitly" +
+                    "[locNodeId=" + node.id() + ", rmtNodeId=" + locNode.id() 
+ "]");
+        }
+    }
+
+    /**
+     * @param nodes Remote nodes.
+     */
+    public void initCompatibilityMode(Collection<ClusterNode> nodes) {
+        boolean mode;
+
+        if (srvcCompatibilitySysProp == null) {
+            boolean clusterHasOldNode = false;
+
+            for (ClusterNode n : nodes) {
+                if 
(n.version().compareToIgnoreTimestamp(LAZY_SERVICES_CFG_SINCE) < 0) {
+                    clusterHasOldNode = true;
+
+                    break;
+                }
+            }
+
+            mode = clusterHasOldNode;
+        }
+        else
+            mode = srvcCompatibilitySysProp;
+
+        while (true) {
+            ServicesCompatibilityState state = compatibilityState.get();
+
+            if (compatibilityState.compareAndSet(state, new 
ServicesCompatibilityState(mode, state.used)))
+                return;
+        }
+    }
+
     /**
      * Service deployment listener.
      */
@@ -1144,10 +1289,18 @@ public class GridServiceProcessor extends 
GridProcessorAdapter {
         @Override public void onUpdated(final Iterable<CacheEntryEvent<?, ?>> 
deps) {
             depExe.submit(new BusyRunnable() {
                 @Override public void run0() {
+                    boolean firstTime = true;
+
                     for (CacheEntryEvent<?, ?> e : deps) {
                         if (!(e.getKey() instanceof GridServiceDeploymentKey))
                             continue;
 
+                        if (firstTime) {
+                            markCompatibilityStateAsUsed();
+
+                            firstTime = false;
+                        }
+
                         GridServiceDeployment dep;
 
                         try {
@@ -1303,12 +1456,20 @@ public class GridServiceProcessor extends 
GridProcessorAdapter {
                                 Iterator<Cache.Entry<Object, Object>> it = 
serviceEntries(
                                     ServiceDeploymentPredicate.INSTANCE);
 
+                                boolean firstTime = true;
+
                                 while (it.hasNext()) {
                                     Cache.Entry<Object, Object> e = it.next();
 
                                     if (!(e.getKey() instanceof 
GridServiceDeploymentKey))
                                         continue;
 
+                                    if (firstTime) {
+                                        markCompatibilityStateAsUsed();
+
+                                        firstTime = false;
+                                    }
+
                                     GridServiceDeployment dep = 
(GridServiceDeployment)e.getValue();
 
                                     try {
@@ -1431,10 +1592,18 @@ public class GridServiceProcessor extends 
GridProcessorAdapter {
         @Override public void onUpdated(final Iterable<CacheEntryEvent<?, ?>> 
assignCol) throws CacheEntryListenerException {
             depExe.submit(new BusyRunnable() {
                 @Override public void run0() {
+                    boolean firstTime = true;
+
                     for (CacheEntryEvent<?, ?> e : assignCol) {
                         if (!(e.getKey() instanceof GridServiceAssignmentsKey))
                             continue;
 
+                        if (firstTime) {
+                            markCompatibilityStateAsUsed();
+
+                            firstTime = false;
+                        }
+
                         GridServiceAssignments assigns;
 
                         try {
@@ -1596,4 +1765,24 @@ public class GridServiceProcessor extends 
GridProcessorAdapter {
             return serviceTopology(ignite.context().cache().utilityCache(), 
svcName);
         }
     }
+
+    /**
+     *
+     */
+    private static class ServicesCompatibilityState {
+        /** */
+        private final boolean srvcCompatibility;
+
+        /** */
+        private final boolean used;
+
+        /**
+         * @param srvcCompatibility Services compatibility mode ({@code true} 
if compatible with old nodes).
+         * @param used Services has been used.
+         */
+        ServicesCompatibilityState(boolean srvcCompatibility, boolean used) {
+            this.srvcCompatibility = srvcCompatibility;
+            this.used = used;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfiguration.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..e0add26
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfiguration.java
@@ -0,0 +1,129 @@
+/*
+ * 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.service;
+
+import org.apache.ignite.internal.util.tostring.GridToStringExclude;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceConfiguration;
+
+/**
+ * Lazy service configuration.
+ */
+public class LazyServiceConfiguration extends ServiceConfiguration {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Service instance. */
+    @GridToStringExclude
+    private transient Service srvc;
+
+    /** */
+    private String srvcClsName;
+
+    /** */
+    private byte[] srvcBytes;
+
+    /**
+     * Default constructor.
+     */
+    public LazyServiceConfiguration() {
+        // No-op.
+    }
+
+    /**
+     * @param cfg Configuration.
+     * @param srvcBytes Marshaller service.
+     */
+    public LazyServiceConfiguration(ServiceConfiguration cfg, byte[] 
srvcBytes) {
+        assert cfg.getService() != null : cfg;
+        assert srvcBytes != null;
+
+        name = cfg.getName();
+        totalCnt = cfg.getTotalCount();
+        maxPerNodeCnt = cfg.getMaxPerNodeCount();
+        cacheName = cfg.getCacheName();
+        affKey = cfg.getAffinityKey();
+        nodeFilter = cfg.getNodeFilter();
+        this.srvcBytes = srvcBytes;
+        srvc = cfg.getService();
+        srvcClsName = srvc.getClass().getName();
+    }
+
+    /**
+     * @return Service bytes.
+     */
+    public byte[] serviceBytes() {
+        return srvcBytes;
+    }
+
+    /**
+     * @return Service class name.
+     */
+    public String serviceClassName() {
+        return srvcClsName;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Service getService() {
+        assert srvc != null : this;
+
+        return srvc;
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("RedundantIfStatement")
+    @Override public boolean equalsIgnoreNodeFilter(Object o) {
+        if (this == o)
+            return true;
+
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        LazyServiceConfiguration that = (LazyServiceConfiguration)o;
+
+        if (maxPerNodeCnt != that.getMaxPerNodeCount())
+            return false;
+
+        if (totalCnt != that.getTotalCount())
+            return false;
+
+        if (affKey != null ? !affKey.equals(that.getAffinityKey()) : 
that.getAffinityKey() != null)
+            return false;
+
+        if (cacheName != null ? !cacheName.equals(that.getCacheName()) : 
that.getCacheName() != null)
+            return false;
+
+        if (name != null ? !name.equals(that.getName()) : that.getName() != 
null)
+            return false;
+
+        if (!F.eq(srvcClsName, that.srvcClsName))
+            return false;
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        String svcCls = srvc == null ? "" : srvc.getClass().getSimpleName();
+        String nodeFilterCls = nodeFilter == null ? "" : 
nodeFilter.getClass().getSimpleName();
+
+        return S.toString(LazyServiceConfiguration.class, this, "svcCls", 
svcCls, "nodeFilterCls", nodeFilterCls);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDescriptorImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDescriptorImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDescriptorImpl.java
index 7671a2e..9ec3eb0 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDescriptorImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDescriptorImpl.java
@@ -19,9 +19,11 @@ package org.apache.ignite.internal.processors.service;
 
 import java.util.Map;
 import java.util.UUID;
+import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceConfiguration;
 import org.apache.ignite.services.ServiceDescriptor;
 import org.jetbrains.annotations.Nullable;
 
@@ -54,7 +56,20 @@ public class ServiceDescriptorImpl implements 
ServiceDescriptor {
 
     /** {@inheritDoc} */
     @Override public Class<? extends Service> serviceClass() {
-        return dep.configuration().getService().getClass();
+        ServiceConfiguration cfg = dep.configuration();
+
+        if (cfg instanceof LazyServiceConfiguration) {
+            String clsName = 
((LazyServiceConfiguration)cfg).serviceClassName();
+
+            try {
+                return (Class<? extends Service>)Class.forName(clsName);
+            }
+            catch (ClassNotFoundException e) {
+                throw new IgniteException("Failed to find service class: " + 
clsName, e);
+            }
+        }
+        else
+            return dep.configuration().getService().getClass();
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/services/ServiceConfiguration.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/services/ServiceConfiguration.java
 
b/modules/core/src/main/java/org/apache/ignite/services/ServiceConfiguration.java
index 126ad47..6698dd4 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/services/ServiceConfiguration.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/services/ServiceConfiguration.java
@@ -55,27 +55,27 @@ public class ServiceConfiguration implements Serializable {
     private static final long serialVersionUID = 0L;
 
     /** Service name. */
-    private String name;
+    protected String name;
 
     /** Service instance. */
     @GridToStringExclude
     private Service svc;
 
     /** Total count. */
-    private int totalCnt;
+    protected int totalCnt;
 
     /** Max per-node count. */
-    private int maxPerNodeCnt;
+    protected int maxPerNodeCnt;
 
     /** Cache name. */
-    private String cacheName;
+    protected String cacheName;
 
     /** Affinity key. */
-    private Object affKey;
+    protected Object affKey;
 
     /** Node filter. */
     @GridToStringExclude
-    private IgnitePredicate<ClusterNode> nodeFilter;
+    protected IgnitePredicate<ClusterNode> nodeFilter;
 
     /**
      * Gets service name.
@@ -301,4 +301,4 @@ public class ServiceConfiguration implements Serializable {
 
         return S.toString(ServiceConfiguration.class, this, "svcCls", svcCls, 
"nodeFilterCls", nodeFilterCls);
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
index 7e0e17f..96192f5 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
@@ -71,6 +71,7 @@ import org.apache.ignite.internal.IgniteNodeAttributes;
 import org.apache.ignite.internal.IgnitionEx;
 import org.apache.ignite.internal.events.DiscoveryCustomEvent;
 import org.apache.ignite.internal.processors.security.SecurityContext;
+import org.apache.ignite.internal.processors.service.GridServiceProcessor;
 import org.apache.ignite.internal.util.GridBoundedLinkedHashSet;
 import org.apache.ignite.internal.util.GridConcurrentHashSet;
 import org.apache.ignite.internal.util.IgniteUtils;
@@ -131,6 +132,7 @@ import org.jsr166.ConcurrentHashMap8;
 
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_DISCOVERY_HISTORY_SIZE;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_OPTIMIZED_MARSHALLER_USE_DEFAULT_SUID;
+import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICES_COMPATIBILITY_MODE;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_BINARY_MARSHALLER_USE_STRING_SERIALIZATION_VER_2;
 import static org.apache.ignite.IgniteSystemProperties.getInteger;
 import static org.apache.ignite.events.EventType.EVT_NODE_FAILED;
@@ -142,6 +144,7 @@ import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER;
 import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_COMPACT_FOOTER;
 import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_USE_BINARY_STRING_SER_VER_2;
 import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_USE_DFLT_SUID;
+import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SERVICES_COMPATIBILITY_MODE;
 import static org.apache.ignite.spi.IgnitePortProtocol.TCP;
 import static 
org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoverySpiState.AUTH_FAILED;
 import static 
org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoverySpiState.CHECK_FAILED;
@@ -3394,6 +3397,75 @@ class ServerImpl extends TcpDiscoveryImpl {
                     return;
                 }
 
+                final Boolean locSrvcCompatibilityEnabled = 
locNode.attribute(ATTR_SERVICES_COMPATIBILITY_MODE);
+
+                if 
(node.version().compareToIgnoreTimestamp(GridServiceProcessor.LAZY_SERVICES_CFG_SINCE)
 >= 0) {
+                    final Boolean rmtSrvcCompatibilityEnabled = 
node.attribute(ATTR_SERVICES_COMPATIBILITY_MODE);
+
+                    if (!F.eq(locSrvcCompatibilityEnabled, 
rmtSrvcCompatibilityEnabled)) {
+                        utilityPool.submit(
+                            new Runnable() {
+                                @Override public void run() {
+                                    String errMsg = "Local node's " + 
IGNITE_SERVICES_COMPATIBILITY_MODE +
+                                        " property value differs from remote 
node's value " +
+                                        "(to make sure all nodes in topology 
have identical IgniteServices compatibility mode, " +
+                                        "configure system property explicitly) 
" +
+                                        "[locSrvcCompatibilityEnabled=" + 
locSrvcCompatibilityEnabled +
+                                        ", rmtSrvcCompatibilityEnabled=" + 
rmtSrvcCompatibilityEnabled +
+                                        ", locNodeAddrs=" + 
U.addressesAsString(locNode) +
+                                        ", rmtNodeAddrs=" + 
U.addressesAsString(node) +
+                                        ", locNodeId=" + locNode.id() + ", 
rmtNodeId=" + msg.creatorNodeId() + ']';
+
+                                    String sndMsg = "Local node's " + 
IGNITE_SERVICES_COMPATIBILITY_MODE +
+                                        " property value differs from remote 
node's value " +
+                                        "(to make sure all nodes in topology 
have identical IgniteServices compatibility mode, " +
+                                        "configure system property explicitly) 
" +
+                                        "[locSrvcCompatibilityEnabled=" + 
rmtSrvcCompatibilityEnabled +
+                                        ", rmtSrvcCompatibilityEnabled=" + 
locSrvcCompatibilityEnabled +
+                                        ", locNodeAddrs=" + 
U.addressesAsString(node) + ", locPort=" + node.discoveryPort() +
+                                        ", rmtNodeAddr=" + 
U.addressesAsString(locNode) + ", locNodeId=" + node.id() +
+                                        ", rmtNodeId=" + locNode.id() + ']';
+
+                                    nodeCheckError(
+                                        node,
+                                        errMsg,
+                                        sndMsg);
+                                }
+                            });
+
+                        // Ignore join request.
+                        return;
+                    }
+                }
+                else if (Boolean.FALSE.equals(locSrvcCompatibilityEnabled)) {
+                    utilityPool.submit(
+                        new Runnable() {
+                            @Override public void run() {
+                                String errMsg = "Remote node doesn't support 
lazy services configuration and " +
+                                    "cannot be joined to local node because 
local node's "
+                                    + IGNITE_SERVICES_COMPATIBILITY_MODE + " 
property value explicitly set to 'false'" +
+                                    "[locNodeAddrs=" + 
U.addressesAsString(locNode) +
+                                    ", rmtNodeAddrs=" + 
U.addressesAsString(node) +
+                                    ", locNodeId=" + locNode.id() + ", 
rmtNodeId=" + node.id() + ']';
+
+                                String sndMsg = "Local node doesn't support 
lazy services configuration and " +
+                                    "cannot be joined to local node because 
remote node's "
+                                    + IGNITE_SERVICES_COMPATIBILITY_MODE + " 
property value explicitly set to 'false'" +
+                                    "[locNodeAddrs=" + 
U.addressesAsString(node) +
+                                    ", rmtNodeAddrs=" + 
U.addressesAsString(locNode) +
+                                    ", locNodeId=" + node.id() + ", 
rmtNodeId=" + locNode.id() + ']';
+
+                                nodeCheckError(
+                                    node,
+                                    errMsg,
+                                    sndMsg);
+                            }
+                        });
+
+                    // Ignore join request.
+                    return;
+                }
+
                 // Handle join.
                 node.internalOrder(ring.nextNodeOrder());
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java
index 28380df..ba8fa5b 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java
@@ -29,6 +29,7 @@ import 
org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_OPTIMIZED_MARSHALLER_USE_DEFAULT_SUID;
+import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICES_COMPATIBILITY_MODE;
 import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_BINARY_MARSHALLER_USE_STRING_SERIALIZATION_VER_2;
 import static org.apache.ignite.configuration.DeploymentMode.CONTINUOUS;
 import static org.apache.ignite.configuration.DeploymentMode.SHARED;
@@ -227,6 +228,68 @@ public abstract class 
GridDiscoveryManagerAttributesSelfTest extends GridCommonA
     /**
      * @throws Exception If failed.
      */
+    public void testServiceCompatibilityEnabled() throws Exception {
+        String backup = System.getProperty(IGNITE_SERVICES_COMPATIBILITY_MODE);
+
+        try {
+            doTestServiceCompatibilityEnabled(true, null, true);
+            doTestServiceCompatibilityEnabled(false, null, true);
+            doTestServiceCompatibilityEnabled(null, false, true);
+            doTestServiceCompatibilityEnabled(true, false, true);
+            doTestServiceCompatibilityEnabled(null, true, true);
+            doTestServiceCompatibilityEnabled(false, true, true);
+
+            doTestServiceCompatibilityEnabled(true, true, false);
+            doTestServiceCompatibilityEnabled(false, false, false);
+            doTestServiceCompatibilityEnabled(null, null, false);
+        }
+        finally {
+            if (backup != null)
+                System.setProperty(IGNITE_SERVICES_COMPATIBILITY_MODE, backup);
+            else
+                System.clearProperty(IGNITE_SERVICES_COMPATIBILITY_MODE);
+        }
+    }
+
+    /**
+     * @param first Service compatibility enabled flag for first node.
+     * @param second Service compatibility enabled flag for second node.
+     * @param fail Fail flag.
+     * @throws Exception If failed.
+     */
+    private void doTestServiceCompatibilityEnabled(Object first, Object 
second, boolean fail) throws Exception {
+        try {
+            if (first != null)
+                System.setProperty(IGNITE_SERVICES_COMPATIBILITY_MODE, 
String.valueOf(first));
+            else
+                System.clearProperty(IGNITE_SERVICES_COMPATIBILITY_MODE);
+
+            startGrid(0);
+
+            if (second != null)
+                System.setProperty(IGNITE_SERVICES_COMPATIBILITY_MODE, 
String.valueOf(second));
+            else
+                System.clearProperty(IGNITE_SERVICES_COMPATIBILITY_MODE);
+
+            try {
+                startGrid(1);
+
+                if (fail)
+                    fail("Node must not join");
+            }
+            catch (Exception e) {
+                if (!fail)
+                    fail("Node must join: " + e.getMessage());
+            }
+        }
+        finally {
+            stopAllGrids();
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testDifferentDeploymentModes() throws Exception {
         startGrid(0);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest.java
new file mode 100644
index 0000000..e77ded7
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest.java
@@ -0,0 +1,259 @@
+/*
+ * 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.service;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.IgniteConfiguration;
+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.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.GridTestExternalClassLoader;
+import org.apache.ignite.testframework.config.GridTestProperties;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+/**
+ * Tests that not all nodes in cluster need user's service definition (only 
nodes according to filter).
+ */
+public class IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest extends 
GridCommonAbstractTest {
+    /** */
+    private static final String NOOP_SERVICE_CLS_NAME = 
"org.apache.ignite.tests.p2p.NoopService";
+
+    /** */
+    private static final String NOOP_SERVICE_2_CLS_NAME = 
"org.apache.ignite.tests.p2p.NoopService2";
+
+    /** IP finder. */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new 
TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    private static final int GRID_CNT = 6;
+
+    /** */
+    private static final String NODE_NAME_ATTR = "NODE_NAME";
+
+    /** */
+    private static final URL[] URLS;
+
+    /** */
+    private static ClassLoader extClsLdr1;
+
+    /** */
+    private static ClassLoader extClsLdr2;
+
+    /** */
+    private Set<String> grp1 = new HashSet<>();
+
+    /** */
+    private Set<String> grp2 = new HashSet<>();
+
+    /** */
+    private boolean client;
+
+    /**
+     * Initialize URLs.
+     */
+    static {
+        try {
+            URLS = new URL[] {new 
URL(GridTestProperties.getProperty("p2p.uri.cls"))};
+        }
+        catch (MalformedURLException e) {
+            throw new RuntimeException("Define property p2p.uri.cls", e);
+        }
+    }
+
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) 
throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        cfg.setPeerClassLoadingEnabled(false);
+
+        TcpDiscoverySpi discoSpi = new TcpDiscoverySpi();
+
+        discoSpi.setIpFinder(IP_FINDER);
+
+        cfg.setDiscoverySpi(discoSpi);
+
+        cfg.setMarshaller(marshaller());
+
+        cfg.setUserAttributes(Collections.singletonMap(NODE_NAME_ATTR, 
gridName));
+
+        if (grp1.contains(gridName))
+            cfg.setClassLoader(extClsLdr1);
+
+        if (grp2.contains(gridName))
+            cfg.setClassLoader(extClsLdr2);
+
+        cfg.setClientMode(client);
+
+        return cfg;
+    }
+
+    /**
+     * @return Marshaller.
+     */
+    protected Marshaller marshaller() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        for (int i = 0; i < GRID_CNT; i += 2)
+            grp1.add(getTestGridName(i));
+
+        for (int i = 1; i < GRID_CNT; i += 2)
+            grp2.add(getTestGridName(i));
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        extClsLdr1 = new GridTestExternalClassLoader(URLS, 
NOOP_SERVICE_2_CLS_NAME);
+        extClsLdr2 = new GridTestExternalClassLoader(URLS, 
NOOP_SERVICE_CLS_NAME);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        extClsLdr1 = null;
+        extClsLdr2 = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testServiceDeployment1() throws Exception {
+        startGrid(0).services().deploy(serviceConfig(true));
+
+        startGrid(1).services().deploy(serviceConfig(false));
+
+        client = true;
+
+        startGrid(2).services().deploy(serviceConfig(true));
+
+        startGrid(3).services().deploy(serviceConfig(false));
+
+        for (int i = 0; i < 4; i++)
+            ignite(i).services().serviceDescriptors();
+
+        ignite(0).services().cancel("TestDeploymentService1");
+
+        ignite(1).services().cancel("TestDeploymentService2");
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testServiceDeployment2() throws Exception {
+        for (int i = 0 ; i < 4; i++)
+            startGrid(i);
+
+        client = true;
+
+        for (int i = 4 ; i < 6; i++)
+            startGrid(i);
+
+        ignite(4).services().deploy(serviceConfig(true));
+
+        ignite(5).services().deploy(serviceConfig(false));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testServiceDeployment3() throws Exception {
+        startGrid(0).services().deploy(serviceConfig(true));
+
+        startGrid(1);
+
+        startGrid(2);
+
+        stopGrid(0);
+
+        awaitPartitionMapExchange();
+
+        ignite(1).services().deploy(serviceConfig(false));
+
+        startGrid(0);
+    }
+
+    /**
+     * @param firstGrp First group flag.
+     * @return Service configuration.
+     * @throws Exception If failed.
+     */
+    private ServiceConfiguration serviceConfig(final boolean firstGrp) throws 
Exception {
+        ServiceConfiguration srvCfg = new ServiceConfiguration();
+
+        srvCfg.setNodeFilter(new TestNodeFilter(firstGrp ? grp1 : grp2));
+
+        Class<Service> srvcCls;
+
+        if (firstGrp)
+            srvcCls = 
(Class<Service>)extClsLdr1.loadClass(NOOP_SERVICE_CLS_NAME);
+        else
+            srvcCls = 
(Class<Service>)extClsLdr2.loadClass(NOOP_SERVICE_2_CLS_NAME);
+
+        Service srvc = srvcCls.newInstance();
+
+        srvCfg.setService(srvc);
+
+        srvCfg.setName("TestDeploymentService" + (firstGrp ? 1 : 2));
+
+        srvCfg.setMaxPerNodeCount(1);
+
+        return srvCfg;
+    }
+
+    /**
+     *
+     */
+    private static class TestNodeFilter implements 
IgnitePredicate<ClusterNode> {
+        /** */
+        private Set<String> grp;
+
+        /**
+         * @param grp Group.
+         */
+        private TestNodeFilter(Set<String> grp) {
+            this.grp = grp;
+        }
+
+        /** {@inheritDoc} */
+        @SuppressWarnings("SuspiciousMethodCalls")
+        @Override public boolean apply(ClusterNode node) {
+            Object gridName = node.attribute(NODE_NAME_ATTR);
+
+            return grp.contains(gridName);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersJdkMarshallerTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersJdkMarshallerTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersJdkMarshallerTest.java
new file mode 100644
index 0000000..f9e24c1
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersJdkMarshallerTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.service;
+
+import org.apache.ignite.marshaller.Marshaller;
+import org.apache.ignite.marshaller.jdk.JdkMarshaller;
+
+/**
+ * Tests that not all nodes in cluster need user's service definition (only 
nodes according to filter).
+ */
+public class IgniteServiceDeployment2ClassLoadersJdkMarshallerTest
+    extends IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest{
+    /** {@inheritDoc} */
+    @Override protected Marshaller marshaller() {
+        return new JdkMarshaller();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest.java
new file mode 100644
index 0000000..f2988cc
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.service;
+
+import org.apache.ignite.marshaller.Marshaller;
+import org.apache.ignite.marshaller.optimized.OptimizedMarshaller;
+
+/**
+ * Tests that not all nodes in cluster need user's service definition (only 
nodes according to filter).
+ */
+public class IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest
+    extends IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest{
+    /** {@inheritDoc} */
+    @Override protected Marshaller marshaller() {
+        return new OptimizedMarshaller(false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingDefaultMarshallerTest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..a8599f4
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingDefaultMarshallerTest.java
@@ -0,0 +1,212 @@
+/*
+ * 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.service;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.IgniteConfiguration;
+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.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;
+
+/**
+ * Tests that not all nodes in cluster need user's service definition (only 
nodes according to filter).
+ */
+public class IgniteServiceDeploymentClassLoadingDefaultMarshallerTest extends 
GridCommonAbstractTest {
+    /** */
+    private static final String NOOP_SERVICE_CLS_NAME = 
"org.apache.ignite.tests.p2p.NoopService";
+
+    /** IP finder. */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new 
TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    private static final int SERVER_NODE = 0;
+
+    /** */
+    private static final int SERVER_NODE_WITH_EXT_CLASS_LOADER = 1;
+
+    /** */
+    private static final int CLIENT_NODE = 2;
+
+    /** */
+    private static final int CLIENT_NODE_WITH_EXT_CLASS_LOADER = 3;
+
+    /** */
+    private static final String NODE_NAME_ATTR = "NODE_NAME";
+
+    /** */
+    private static ClassLoader extClsLdr;
+
+    /** */
+    private Set<String> extClsLdrGrids = new HashSet<>();
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) 
throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        cfg.setPeerClassLoadingEnabled(false);
+
+        TcpDiscoverySpi discoSpi = new TcpDiscoverySpi();
+
+        discoSpi.setIpFinder(IP_FINDER);
+
+        cfg.setDiscoverySpi(discoSpi);
+
+        cfg.setMarshaller(marshaller());
+
+        cfg.setUserAttributes(Collections.singletonMap(NODE_NAME_ATTR, 
gridName));
+
+        if (getTestGridName(CLIENT_NODE_WITH_EXT_CLASS_LOADER).equals(gridName)
+            || getTestGridName(CLIENT_NODE).equals(gridName))
+            cfg.setClientMode(true);
+
+        if (extClsLdrGrids.contains(gridName))
+            cfg.setClassLoader(extClsLdr);
+
+        return cfg;
+    }
+
+    /**
+     * @return Marshaller.
+     */
+    protected Marshaller marshaller() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        extClsLdrGrids.clear();
+
+        extClsLdrGrids.add(getTestGridName(SERVER_NODE_WITH_EXT_CLASS_LOADER));
+        extClsLdrGrids.add(getTestGridName(CLIENT_NODE_WITH_EXT_CLASS_LOADER));
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        extClsLdr = getExternalClassLoader();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        extClsLdr = null;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testServiceDeployment1() throws Exception {
+        startGrid(SERVER_NODE);
+
+        
startGrid(SERVER_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig());
+
+        startGrid(CLIENT_NODE);
+
+        
startGrid(CLIENT_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig());
+
+        ignite(SERVER_NODE).services().serviceDescriptors();
+
+        
ignite(SERVER_NODE_WITH_EXT_CLASS_LOADER).services().serviceDescriptors();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testServiceDeployment2() throws Exception {
+        startGrid(SERVER_NODE);
+
+        
startGrid(CLIENT_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig());
+
+        startGrid(CLIENT_NODE);
+
+        
startGrid(SERVER_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testServiceDeployment3() throws Exception {
+        
startGrid(SERVER_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig());
+
+        startGrid(SERVER_NODE);
+
+        startGrid(CLIENT_NODE);
+
+        
startGrid(CLIENT_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig());
+    }
+
+    /**
+     * @return Service configuration.
+     * @throws Exception If failed.
+     */
+    private ServiceConfiguration serviceConfig() throws Exception {
+        ServiceConfiguration srvCfg = new ServiceConfiguration();
+
+        srvCfg.setNodeFilter(new TestNodeFilter(extClsLdrGrids));
+
+        Class<Service> srvcCls = 
(Class<Service>)extClsLdr.loadClass(NOOP_SERVICE_CLS_NAME);
+
+        Service srvc = srvcCls.newInstance();
+
+        srvCfg.setService(srvc);
+
+        srvCfg.setName("TestDeploymentService");
+
+        srvCfg.setMaxPerNodeCount(1);
+
+        return srvCfg;
+    }
+
+    /**
+     *
+     */
+    private static class TestNodeFilter implements 
IgnitePredicate<ClusterNode> {
+        /** */
+        private static final long serialVersionUID = 0;
+
+        /** */
+        private Set<String> grids;
+
+        /**
+         * @param grids Grid names.
+         */
+        private TestNodeFilter(Set<String> grids) {
+            this.grids = grids;
+        }
+
+        /** {@inheritDoc} */
+        @SuppressWarnings("SuspiciousMethodCalls")
+        @Override public boolean apply(ClusterNode node) {
+            return grids.contains(node.attribute(NODE_NAME_ATTR));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingJdkMarshallerTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingJdkMarshallerTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingJdkMarshallerTest.java
new file mode 100644
index 0000000..aeb68af
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingJdkMarshallerTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.service;
+
+import org.apache.ignite.marshaller.Marshaller;
+import org.apache.ignite.marshaller.jdk.JdkMarshaller;
+
+/**
+ * Tests that not all nodes in cluster need user's service definition (only 
nodes according to filter).
+ */
+public class IgniteServiceDeploymentClassLoadingJdkMarshallerTest
+    extends IgniteServiceDeploymentClassLoadingDefaultMarshallerTest {
+    /** {@inheritDoc} */
+    @Override protected Marshaller marshaller() {
+        return new JdkMarshaller();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest.java
new file mode 100644
index 0000000..cb0c911
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.service;
+
+import org.apache.ignite.marshaller.Marshaller;
+import org.apache.ignite.marshaller.optimized.OptimizedMarshaller;
+
+/**
+ * Tests that not all nodes in cluster need user's service definition (only 
nodes according to filter).
+ */
+public class IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest
+    extends IgniteServiceDeploymentClassLoadingDefaultMarshallerTest {
+    /** {@inheritDoc} */
+    @Override protected Marshaller marshaller() {
+        return new OptimizedMarshaller(false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java
 
b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java
index a8d6e5c..28974ea 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java
@@ -57,6 +57,12 @@ import 
org.apache.ignite.internal.processors.service.GridServiceProcessorStopSel
 import 
org.apache.ignite.internal.processors.service.GridServiceProxyNodeStopSelfTest;
 import 
org.apache.ignite.internal.processors.service.GridServiceReassignmentSelfTest;
 import 
org.apache.ignite.internal.processors.service.GridServiceSerializationSelfTest;
+import 
org.apache.ignite.internal.processors.service.IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest;
+import 
org.apache.ignite.internal.processors.service.IgniteServiceDeployment2ClassLoadersJdkMarshallerTest;
+import 
org.apache.ignite.internal.processors.service.IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest;
+import 
org.apache.ignite.internal.processors.service.IgniteServiceDeploymentClassLoadingDefaultMarshallerTest;
+import 
org.apache.ignite.internal.processors.service.IgniteServiceDeploymentClassLoadingJdkMarshallerTest;
+import 
org.apache.ignite.internal.processors.service.IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest;
 import 
org.apache.ignite.internal.processors.service.ServicePredicateAccessCacheTest;
 import 
org.apache.ignite.internal.util.GridStartupWithSpecifiedWorkDirectorySelfTest;
 import 
org.apache.ignite.internal.util.GridStartupWithUndefinedIgniteHomeSelfTest;
@@ -130,6 +136,13 @@ public class IgniteKernalSelfTestSuite extends TestSuite {
         suite.addTestSuite(GridServiceSerializationSelfTest.class);
         suite.addTestSuite(GridServiceProxyNodeStopSelfTest.class);
 
+        
suite.addTestSuite(IgniteServiceDeploymentClassLoadingDefaultMarshallerTest.class);
+        
suite.addTestSuite(IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest.class);
+        
suite.addTestSuite(IgniteServiceDeploymentClassLoadingJdkMarshallerTest.class);
+        
suite.addTestSuite(IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest.class);
+        
suite.addTestSuite(IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest.class);
+        
suite.addTestSuite(IgniteServiceDeployment2ClassLoadersJdkMarshallerTest.class);
+
         return suite;
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService.java
----------------------------------------------------------------------
diff --git 
a/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService.java
 
b/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService.java
new file mode 100644
index 0000000..b3d06b2
--- /dev/null
+++ 
b/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService.java
@@ -0,0 +1,41 @@
+/*
+ * 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.tests.p2p;
+
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceContext;
+
+/**
+ * No-op service.
+ */
+public class NoopService implements Service {
+    /** {@inheritDoc} */
+    @Override public void cancel(ServiceContext ctx) {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void init(ServiceContext ctx) throws Exception {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void execute(ServiceContext ctx) throws Exception {
+        // No-op.
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService2.java
----------------------------------------------------------------------
diff --git 
a/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService2.java
 
b/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService2.java
new file mode 100644
index 0000000..ad65d5b
--- /dev/null
+++ 
b/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService2.java
@@ -0,0 +1,41 @@
+/*
+ * 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.tests.p2p;
+
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceContext;
+
+/**
+ * No-op service.
+ */
+public class NoopService2 implements Service {
+    /** {@inheritDoc} */
+    @Override public void cancel(ServiceContext ctx) {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void init(ServiceContext ctx) throws Exception {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void execute(ServiceContext ctx) throws Exception {
+        // No-op.
+    }
+}

Reply via email to