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

alexpl 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 6721ab9d020 IGNITE-22464 Java thin client: Add events for client start 
and stop - Fixes #11387.
6721ab9d020 is described below

commit 6721ab9d020a606a6fd5405dcbbc36909271526b
Author: Aleksey Plekhanov <[email protected]>
AuthorDate: Thu Jun 13 16:30:15 2024 +0500

    IGNITE-22464 Java thin client: Add events for client start and stop - Fixes 
#11387.
    
    Signed-off-by: Aleksey Plekhanov <[email protected]>
---
 .../ignite/client/events/ClientFailEvent.java      | 54 +++++++++++++
 .../ignite/client/events/ClientLifecycleEvent.java | 25 ++++++
 .../events/ClientLifecycleEventListener.java       | 44 ++++++++++
 .../ignite/client/events/ClientStartEvent.java     | 55 +++++++++++++
 .../ignite/client/events/ClientStopEvent.java      | 42 ++++++++++
 .../internal/client/thin/TcpIgniteClient.java      | 56 ++++++++++++-
 .../IgniteClientLifecycleEventListenerTest.java    | 94 ++++++++++++++++++++++
 .../org/apache/ignite/client/ClientTestSuite.java  |  2 +
 8 files changed, 371 insertions(+), 1 deletion(-)

diff --git 
a/modules/core/src/main/java/org/apache/ignite/client/events/ClientFailEvent.java
 
b/modules/core/src/main/java/org/apache/ignite/client/events/ClientFailEvent.java
new file mode 100644
index 00000000000..a6e1592cee6
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/client/events/ClientFailEvent.java
@@ -0,0 +1,54 @@
+/*
+ * 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.client.events;
+
+import org.apache.ignite.configuration.ClientConfiguration;
+
+/**
+ * Event, triggered when Ignite client is failed to start.
+ */
+public class ClientFailEvent implements ClientLifecycleEvent {
+    /** */
+    private final ClientConfiguration cfg;
+
+    /** */
+    private final Throwable throwable;
+
+    /**
+     * @param cfg Client configuration.
+     * @param throwable Throwable that caused the failure.
+     */
+    public ClientFailEvent(ClientConfiguration cfg, Throwable throwable) {
+        this.cfg = cfg;
+        this.throwable = throwable;
+    }
+
+    /**
+     * @return Client configuration.
+     */
+    public ClientConfiguration configuration() {
+        return cfg;
+    }
+
+    /**
+     * @return A cause of the failure.
+     */
+    public Throwable throwable() {
+        return throwable;
+    }
+}
diff --git 
a/modules/core/src/main/java/org/apache/ignite/client/events/ClientLifecycleEvent.java
 
b/modules/core/src/main/java/org/apache/ignite/client/events/ClientLifecycleEvent.java
new file mode 100644
index 00000000000..ffc277157c1
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/client/events/ClientLifecycleEvent.java
@@ -0,0 +1,25 @@
+/*
+ * 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.client.events;
+
+/**
+ * Marker interface for all client's lifecycle events.
+ */
+public interface ClientLifecycleEvent {
+    // No-op.
+}
diff --git 
a/modules/core/src/main/java/org/apache/ignite/client/events/ClientLifecycleEventListener.java
 
b/modules/core/src/main/java/org/apache/ignite/client/events/ClientLifecycleEventListener.java
new file mode 100644
index 00000000000..98fe8080ac3
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/client/events/ClientLifecycleEventListener.java
@@ -0,0 +1,44 @@
+/*
+ * 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.client.events;
+
+import java.util.EventListener;
+
+/** */
+public interface ClientLifecycleEventListener extends EventListener {
+    /**
+     * @param evt Client start event.
+     */
+    public default void onClientStart(ClientStartEvent evt) {
+        // No-op.
+    }
+
+    /**
+     * @param evt Client fail event.
+     */
+    public default void onClientFail(ClientFailEvent evt) {
+        // No-op.
+    }
+
+    /**
+     * @param evt Client stop event.
+     */
+    public default void onClientStop(ClientStopEvent evt) {
+        // No-op.
+    }
+}
diff --git 
a/modules/core/src/main/java/org/apache/ignite/client/events/ClientStartEvent.java
 
b/modules/core/src/main/java/org/apache/ignite/client/events/ClientStartEvent.java
new file mode 100644
index 00000000000..9aa71d55d6e
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/client/events/ClientStartEvent.java
@@ -0,0 +1,55 @@
+/*
+ * 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.client.events;
+
+import org.apache.ignite.client.IgniteClient;
+import org.apache.ignite.configuration.ClientConfiguration;
+
+/**
+ * Event, triggered when Ignite client is started.
+ */
+public class ClientStartEvent implements ClientLifecycleEvent {
+    /** */
+    private final IgniteClient client;
+
+    /** */
+    private final ClientConfiguration cfg;
+
+    /**
+     * @param client Ignite client instance.
+     * @param cfg Client configuration.
+     */
+    public ClientStartEvent(IgniteClient client, ClientConfiguration cfg) {
+        this.client = client;
+        this.cfg = cfg;
+    }
+
+    /**
+     * @return Client configuration.
+     */
+    public ClientConfiguration configuration() {
+        return cfg;
+    }
+
+    /**
+     * @return Ignite client instance.
+     */
+    public IgniteClient client() {
+        return client;
+    }
+}
diff --git 
a/modules/core/src/main/java/org/apache/ignite/client/events/ClientStopEvent.java
 
b/modules/core/src/main/java/org/apache/ignite/client/events/ClientStopEvent.java
new file mode 100644
index 00000000000..5293f172556
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/client/events/ClientStopEvent.java
@@ -0,0 +1,42 @@
+/*
+ * 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.client.events;
+
+import org.apache.ignite.client.IgniteClient;
+
+/**
+ * Event, triggered when Ignite client is stopped.
+ */
+public class ClientStopEvent implements ClientLifecycleEvent {
+    /** */
+    private final IgniteClient client;
+
+    /**
+     * @param client Ignite client instance.
+     */
+    public ClientStopEvent(IgniteClient client) {
+        this.client = client;
+    }
+
+    /**
+     * @return Ignite client instance.
+     */
+    public IgniteClient client() {
+        return client;
+    }
+}
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/TcpIgniteClient.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/TcpIgniteClient.java
index a4d9922143f..48c490198cb 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/TcpIgniteClient.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/TcpIgniteClient.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.client.thin;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.EventListener;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -50,6 +51,10 @@ import org.apache.ignite.client.ClientServices;
 import org.apache.ignite.client.ClientTransactions;
 import org.apache.ignite.client.IgniteClient;
 import org.apache.ignite.client.IgniteClientFuture;
+import org.apache.ignite.client.events.ClientFailEvent;
+import org.apache.ignite.client.events.ClientLifecycleEventListener;
+import org.apache.ignite.client.events.ClientStartEvent;
+import org.apache.ignite.client.events.ClientStopEvent;
 import org.apache.ignite.configuration.BinaryConfiguration;
 import org.apache.ignite.configuration.ClientConfiguration;
 import org.apache.ignite.configuration.ClientTransactionConfiguration;
@@ -68,6 +73,7 @@ import 
org.apache.ignite.internal.client.thin.io.ClientConnectionMultiplexer;
 import org.apache.ignite.internal.processors.platform.client.ClientStatus;
 import 
org.apache.ignite.internal.processors.platform.client.IgniteClientException;
 import org.apache.ignite.internal.util.GridArgumentCheck;
+import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.logger.NullLogger;
@@ -101,6 +107,9 @@ public class TcpIgniteClient implements IgniteClient {
     /** Registered entry listeners for all caches. */
     private final ClientCacheEntryListenersRegistry lsnrsRegistry;
 
+    /** Event listeners. */
+    private final EventListener[] evtLsnrs;
+
     /** Marshaller. */
     private final ClientBinaryMarshaller marsh;
 
@@ -140,6 +149,8 @@ public class TcpIgniteClient implements IgniteClient {
 
         ch = new ReliableChannel(chFactory, cfg, binary);
 
+        evtLsnrs = cfg.getEventListeners() == null ? null : 
cfg.getEventListeners().clone();
+
         try {
             ch.channelsInit();
 
@@ -177,6 +188,10 @@ public class TcpIgniteClient implements IgniteClient {
     /** {@inheritDoc} */
     @Override public void close() {
         ch.close();
+
+        ClientStopEvent evt = new ClientStopEvent(this);
+
+        triggerLifecycleEventListeners(log, evtLsnrs, lsnr -> 
lsnr.onClientStop(evt));
     }
 
     /** {@inheritDoc} */
@@ -423,7 +438,46 @@ public class TcpIgniteClient implements IgniteClient {
      * @return Client with successfully opened thin client connection.
      */
     public static IgniteClient start(ClientConfiguration cfg) throws 
ClientException {
-        return new TcpIgniteClient(cfg);
+        try {
+            TcpIgniteClient client = new TcpIgniteClient(cfg);
+
+            ClientStartEvent evt = new ClientStartEvent(client, cfg);
+
+            triggerLifecycleEventListeners(client.log, client.evtLsnrs, lsnr 
-> lsnr.onClientStart(evt));
+
+            return client;
+        }
+        catch (Throwable throwable) {
+            ClientFailEvent evt = new ClientFailEvent(cfg, throwable);
+
+            triggerLifecycleEventListeners(cfg.getLogger(), 
cfg.getEventListeners(), lsnr -> lsnr.onClientFail(evt));
+
+            throw throwable;
+        }
+    }
+
+    /** */
+    private static void triggerLifecycleEventListeners(
+        @Nullable IgniteLogger log,
+        EventListener[] lsnrs,
+        Consumer<ClientLifecycleEventListener> action
+    ) {
+        if (F.isEmpty(lsnrs))
+            return;
+
+        for (EventListener lsnr: lsnrs) {
+            if (lsnr instanceof ClientLifecycleEventListener) {
+                try {
+                    ClientLifecycleEventListener lsnr0 = 
(ClientLifecycleEventListener)lsnr;
+
+                    action.accept(lsnr0);
+                }
+                catch (Exception e) {
+                    if (log != null)
+                        log.warning("Exception thrown while consuming event in 
listener " + lsnr, e);
+                }
+            }
+        }
     }
 
     /**
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/client/thin/events/IgniteClientLifecycleEventListenerTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/client/thin/events/IgniteClientLifecycleEventListenerTest.java
new file mode 100644
index 00000000000..82e18d60433
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/client/thin/events/IgniteClientLifecycleEventListenerTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.client.thin.events;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.client.IgniteClient;
+import org.apache.ignite.client.events.ClientFailEvent;
+import org.apache.ignite.client.events.ClientLifecycleEvent;
+import org.apache.ignite.client.events.ClientLifecycleEventListener;
+import org.apache.ignite.client.events.ClientStartEvent;
+import org.apache.ignite.client.events.ClientStopEvent;
+import org.apache.ignite.configuration.ClientConfiguration;
+import org.apache.ignite.internal.client.thin.AbstractThinClientTest;
+import org.junit.Test;
+
+/**
+ * Tests lifecycle event listeners of a thin client.
+ */
+public class IgniteClientLifecycleEventListenerTest extends 
AbstractThinClientTest {
+    /** */
+    List<ClientLifecycleEvent> evts = new ArrayList<>();
+
+    /** {@inheritDoc} */
+    @Override protected ClientConfiguration getClientConfiguration() {
+        return super.getClientConfiguration()
+            .setEventListeners(new ClientLifecycleEventListener() {
+                @Override public void onClientStart(ClientStartEvent evt) {
+                    evts.add(evt);
+                }
+
+                @Override public void onClientFail(ClientFailEvent evt) {
+                    evts.add(evt);
+                }
+
+                @Override public void onClientStop(ClientStopEvent evt) {
+                    evts.add(evt);
+                }
+            });
+    }
+
+    /** */
+    @Test
+    public void testClientLifecycleEvents() throws Exception {
+        evts.clear();
+
+        startGrids(3);
+
+        IgniteClient client0;
+
+        try (IgniteClient client = startClient(0, 1, 2)) {
+            client0 = client;
+
+            assertEquals(1, evts.size());
+            ClientLifecycleEvent evt0 = evts.get(0);
+            assertTrue(evt0 instanceof ClientStartEvent);
+            assertEquals(client, ((ClientStartEvent)evt0).client());
+            assertEquals(3, 
((ClientStartEvent)evt0).configuration().getAddresses().length);
+        }
+
+        assertEquals(2, evts.size());
+        ClientLifecycleEvent evt1 = evts.get(1);
+        assertTrue(evt1 instanceof ClientStopEvent);
+        assertEquals(client0, ((ClientStopEvent)evt1).client());
+
+        try {
+            
Ignition.startClient(getClientConfiguration().setAddresses("failure"));
+            fail();
+        }
+        catch (Exception e) {
+            assertEquals(3, evts.size());
+            ClientLifecycleEvent evt2 = evts.get(2);
+            assertTrue(evt2 instanceof ClientFailEvent);
+            assertEquals(1, 
((ClientFailEvent)evt2).configuration().getAddresses().length);
+            assertEquals(e, ((ClientFailEvent)evt2).throwable());
+        }
+    }
+}
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/client/ClientTestSuite.java 
b/modules/indexing/src/test/java/org/apache/ignite/client/ClientTestSuite.java
index a013e7f69b4..9329e2377b3 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/client/ClientTestSuite.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/client/ClientTestSuite.java
@@ -45,6 +45,7 @@ import 
org.apache.ignite.internal.client.thin.ThinClientPartitionAwarenessStable
 import 
org.apache.ignite.internal.client.thin.ThinClientPartitionAwarenessUnstableTopologyTest;
 import org.apache.ignite.internal.client.thin.TimeoutTest;
 import 
org.apache.ignite.internal.client.thin.events.IgniteClientConnectionEventListenerTest;
+import 
org.apache.ignite.internal.client.thin.events.IgniteClientLifecycleEventListenerTest;
 import 
org.apache.ignite.internal.client.thin.events.IgniteClientRequestEventListenerTest;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
@@ -90,6 +91,7 @@ import org.junit.runners.Suite;
     MetadataRegistrationTest.class,
     IgniteClientConnectionEventListenerTest.class,
     IgniteClientRequestEventListenerTest.class,
+    IgniteClientLifecycleEventListenerTest.class,
     ThinClientEnpointsDiscoveryTest.class,
     InactiveClusterCacheRequestTest.class,
     AffinityMetricsTest.class,

Reply via email to