diff --git a/appserver/extras/payara-micro/payara-micro-distribution/pom.xml b/appserver/extras/payara-micro/payara-micro-distribution/pom.xml
index 54537f606f7..a205eeaff6c 100644
--- a/appserver/extras/payara-micro/payara-micro-distribution/pom.xml
+++ b/appserver/extras/payara-micro/payara-micro-distribution/pom.xml
@@ -41,7 +41,7 @@
-->
4.0.0
-
+
fish.payara.extras.payara-micro
payara-micro-parent
@@ -51,9 +51,9 @@
fish.payara.extras
payara-micro
jar
-
+
Payara Micro Distribution
-
+
install
@@ -212,7 +212,7 @@
zip
true
-
+
org.glassfish.main.ejb
@@ -246,7 +246,7 @@
true
-
+
org.glassfish.main.packager
glassfish-jsf
@@ -296,7 +296,7 @@
zip
true
-
+
org.glassfish.main.packager
@@ -305,7 +305,7 @@
zip
true
-
+
org.glassfish.main.packager
@@ -314,7 +314,7 @@
zip
true
-
+
org.glassfish.main.packager
@@ -323,7 +323,7 @@
zip
true
-
+
org.glassfish.main.packager
@@ -332,7 +332,7 @@
zip
true
-
+
org.glassfish.main.packager
@@ -341,7 +341,7 @@
zip
true
-
+
org.glassfish.main.packager
@@ -350,7 +350,7 @@
zip
true
-
+
org.glassfish.main.packager
@@ -359,7 +359,7 @@
zip
true
-
+
org.glassfish.main.packager
@@ -368,7 +368,7 @@
zip
true
-
+
fish.payara.micro
@@ -377,7 +377,7 @@
jar
true
-
+
fish.payara.micro
@@ -386,7 +386,7 @@
jar
true
-
+
fish.payara.micro
@@ -395,7 +395,7 @@
jar
true
-
+
fish.payara.micro
@@ -404,7 +404,7 @@
jar
true
-
+
org.glassfish.main.batch
@@ -427,7 +427,7 @@
jar
true
-
+
fish.payara.ejb.timer
@@ -436,6 +436,13 @@
jar
true
+
+ fish.payara.persistence.coordination
+ hazelcast-eclipselink-coordination
+ ${project.version}
+ jar
+ true
+
fish.payara.jmx.monitoring
jmx-monitoring
@@ -443,7 +450,7 @@
jar
true
-
+
org.glassfish.main.jms
@@ -466,9 +473,9 @@
${project.version}
zip
true
-
+
-
+
diff --git a/appserver/packager/glassfish-jpa/pom.xml b/appserver/packager/glassfish-jpa/pom.xml
index 27376d96203..ce2335c8ce1 100644
--- a/appserver/packager/glassfish-jpa/pom.xml
+++ b/appserver/packager/glassfish-jpa/pom.xml
@@ -83,7 +83,7 @@
ips
- false
+ false
@@ -121,7 +121,7 @@
-
+
@@ -181,6 +181,12 @@
org.eclipse.persistence
org.eclipse.persistence.asm
+
+
+ fish.payara.persistence.coordination
+ hazelcast-eclipselink-coordination
+ ${project.version}
+
diff --git a/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/pom.xml b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/pom.xml
new file mode 100644
index 00000000000..4cf7db2597d
--- /dev/null
+++ b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+
+ org.glassfish.main
+ payara-appserver-modules
+ 5.182-SNAPSHOT
+
+ fish.payara.persistence.coordination
+ hazelcast-eclipselink-coordination
+ glassfish-jar
+ HZ Eclipselink Coordination
+ Hazelcast Based Eclipselink L2 Cache Coordination
+
+
+ svendiedrichsen
+ Sven Diedrichsen
+
+ developer
+
+
+
+
+
+ fish.payara.payara-modules
+ payara-executor-service
+ ${project.version}
+
+
+ fish.payara.payara-modules
+ hazelcast-bootstrap
+ ${project.version}
+ jar
+
+
+ org.eclipse.persistence
+ org.eclipse.persistence.core
+
+
+
diff --git a/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastPayload.java b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastPayload.java
new file mode 100644
index 00000000000..0c9afe8aabc
--- /dev/null
+++ b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastPayload.java
@@ -0,0 +1,116 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2016-2018 Payara Foundation and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://github.com/payara/Payara/blob/master/LICENSE.txt
+ * See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * The Payara Foundation designates this particular file as subject to the "Classpath"
+ * exception as provided by the Payara Foundation in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+package fish.payara.persistence.eclipselink.cache.coordination;
+
+import org.eclipse.persistence.internal.sessions.AbstractSession;
+import org.eclipse.persistence.sessions.coordination.RemoteCommandManager;
+import org.eclipse.persistence.sessions.serializers.JavaSerializer;
+import org.eclipse.persistence.sessions.serializers.Serializer;
+
+import java.io.Serializable;
+import java.util.UUID;
+
+/**
+ * Represents the payload transported via Hazelcast topic.
+ *
+ * @author Sven Diedrichsen
+ */
+public abstract class HazelcastPayload implements Serializable {
+
+ private static final long serialVersionUID = 1;
+
+ /**
+ * This payloads id.
+ */
+ private final UUID id = UUID.randomUUID();
+
+ public abstract org.eclipse.persistence.sessions.coordination.Command getCommand(RemoteCommandManager rcm);
+
+ public UUID getId() { return id; }
+
+ /**
+ * Implements a payload for raw bytes to transfer.
+ */
+ public static class Bytes extends HazelcastPayload {
+
+ private final byte[] bytes;
+
+ public Bytes(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ /**
+ * Returns the serialized {@link org.eclipse.persistence.sessions.coordination.Command} from
+ * the provided bytes.
+ * @param rcm The {@link RemoteCommandManager} to use for serialization.
+ * @return coordination command serialized from bytes.
+ */
+ public org.eclipse.persistence.sessions.coordination.Command getCommand(RemoteCommandManager rcm) {
+ Serializer serializer = rcm.getSerializer();
+ if (serializer == null) {
+ serializer = JavaSerializer.instance;
+ }
+ return (org.eclipse.persistence.sessions.coordination.Command)serializer.deserialize(this.bytes, (AbstractSession) rcm.getCommandProcessor());
+ }
+ }
+
+ /**
+ * Implements a payload consisting of a coordination command.
+ */
+ public static class Command extends HazelcastPayload {
+
+ private final org.eclipse.persistence.sessions.coordination.Command command;
+
+ public Command(org.eclipse.persistence.sessions.coordination.Command command) {
+ this.command = command;
+ }
+
+ /**
+ * Simply returns the original command.
+ * @param rcm The {@link RemoteCommandManager} to use for serialization. Will not be used.
+ * @return The original command.
+ */
+ @Override
+ public org.eclipse.persistence.sessions.coordination.Command getCommand(RemoteCommandManager rcm) {
+ return this.command;
+ }
+ }
+
+}
diff --git a/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastPublishingTransportManager.java b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastPublishingTransportManager.java
new file mode 100644
index 00000000000..f1cdbe65bee
--- /dev/null
+++ b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastPublishingTransportManager.java
@@ -0,0 +1,99 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2016-2018 Payara Foundation and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://github.com/payara/Payara/blob/master/LICENSE.txt
+ * See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * The Payara Foundation designates this particular file as subject to the "Classpath"
+ * exception as provided by the Payara Foundation in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+package fish.payara.persistence.eclipselink.cache.coordination;
+
+import org.eclipse.persistence.internal.sessions.coordination.RemoteConnection;
+import org.eclipse.persistence.sessions.coordination.broadcast.BroadcastTransportManager;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * Hazelcast based {@link BroadcastTransportManager}.
+ *
+ * @author Sven Diedrichsen
+ */
+public class HazelcastPublishingTransportManager extends BroadcastTransportManager {
+
+ private static final Logger LOG = Logger.getLogger(HazelcastPublishingTransportManager.class.getName());
+ /**
+ * The connection with the hz topic.
+ */
+ private HazelcastTopicRemoteConnection connection;
+
+ public HazelcastPublishingTransportManager() {
+ super();
+ LOG.info("HazelcastPublishingTransportManager initialized.");
+ }
+
+ /**
+ * Method to return the connection with the hazelcast topic.
+ *
+ * @return Map containing the hz connection.
+ */
+ @Override
+ public Map getConnectionsToExternalServicesForCommandPropagation() {
+ if (this.connection != null) {
+ return Collections.singletonMap(this.connection.getServiceId().getId(), this.connection);
+ }
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Creates the hz connection.
+ */
+ @Override
+ public void createLocalConnection() {
+ this.connection = new HazelcastTopicRemoteConnection(this.getRemoteCommandManager());
+ }
+
+ /**
+ * Closes and removes the connection.
+ */
+ @Override
+ public void removeLocalConnection() {
+ if (this.connection != null) {
+ this.connection.close();
+ this.connection = null;
+ }
+ }
+
+}
diff --git a/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastTopic.java b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastTopic.java
new file mode 100644
index 00000000000..1cb71e09b73
--- /dev/null
+++ b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastTopic.java
@@ -0,0 +1,110 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2016-2018 Payara Foundation and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://github.com/payara/Payara/blob/master/LICENSE.txt
+ * See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * The Payara Foundation designates this particular file as subject to the "Classpath"
+ * exception as provided by the Payara Foundation in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+package fish.payara.persistence.eclipselink.cache.coordination;
+
+import fish.payara.nucleus.eventbus.MessageReceiver;
+
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+/**
+ * Representation of the Hazelcast topic to allow for proxying.
+ *
+ * @author Sven Diedrichsen
+ */
+final class HazelcastTopic {
+
+ /**
+ * The topic name to use.
+ */
+ private final String name;
+ /**
+ * The message listener id to unregister with.
+ */
+ private final String messageListenerId;
+ /**
+ * Stores the Ids of the messages published by this topic.
+ */
+ private final Set publishedMessageIds = new ConcurrentSkipListSet<>();
+
+ /**
+ * Ctor.
+ * @param name The name of the topic.
+ */
+ HazelcastTopic(String name, MessageReceiver receiver) {
+ this.name = name;
+ this.messageListenerId = getStorage().registerMessageReceiver(name, receiver);
+ }
+
+ /**
+ * Publishes the command.
+ * @param payload The {@link HazelcastPayload} to publish.
+ */
+ void publish(HazelcastPayload payload) {
+ publishedMessageIds.add(payload.getId());
+ getStorage().publish(name, payload);
+ }
+
+ /**
+ * Checks if the provided payload has been published by this topic.
+ * @param payload The payload to check if it has been published with this topic.
+ * @return True if it has been published.
+ */
+ boolean hasPublished(HazelcastPayload payload) {
+ return publishedMessageIds.remove(payload.getId());
+ }
+
+ /**
+ * Destroys the referenced topic.
+ */
+ void destroy() {
+ publishedMessageIds.clear();
+ getStorage().removeMessageReceiver(messageListenerId);
+ }
+
+ /**
+ * @return The hz topic storage.
+ */
+ private HazelcastTopicStorage getStorage() {
+ return HazelcastTopicStorage.getInstance();
+ }
+
+}
diff --git a/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastTopicRemoteConnection.java b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastTopicRemoteConnection.java
new file mode 100644
index 00000000000..fb6d4190191
--- /dev/null
+++ b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastTopicRemoteConnection.java
@@ -0,0 +1,115 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2016-2018 Payara Foundation and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://github.com/payara/Payara/blob/master/LICENSE.txt
+ * See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * The Payara Foundation designates this particular file as subject to the "Classpath"
+ * exception as provided by the Payara Foundation in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+package fish.payara.persistence.eclipselink.cache.coordination;
+
+import com.hazelcast.core.MessageListener;
+import fish.payara.nucleus.eventbus.ClusterMessage;
+import fish.payara.nucleus.eventbus.MessageReceiver;
+import org.eclipse.persistence.internal.sessions.coordination.broadcast.BroadcastRemoteConnection;
+import org.eclipse.persistence.sessions.coordination.Command;
+import org.eclipse.persistence.sessions.coordination.RemoteCommandManager;
+
+/**
+ * Hazelcast {@link BroadcastRemoteConnection} implementing the HZ {@link MessageListener} interface.
+ *
+ * @author Sven Diedrichsen
+ */
+public class HazelcastTopicRemoteConnection extends BroadcastRemoteConnection implements MessageReceiver {
+
+ /**
+ * The topic to publish commands to and receive messages from.
+ */
+ private final HazelcastTopic topic;
+
+ HazelcastTopicRemoteConnection(RemoteCommandManager rcm) {
+ super(rcm);
+ this.topic = new HazelcastTopic(rcm.getChannel(), this);
+ }
+
+ /**
+ * Publishes the provided command via {@link HazelcastTopic}.
+ * @param o The command to execute.
+ * @return NULL
+ * @throws Exception In case of an error.
+ */
+ @Override
+ protected Object executeCommandInternal(Object o) throws Exception {
+ if (o != null) {
+ Object[] debugInfo = null;
+ if (this.rcm.shouldLogDebugMessage()) {
+ debugInfo = this.logDebugBeforePublish(null);
+ }
+ if(Command.class.isAssignableFrom(o.getClass())) {
+ this.topic.publish(new HazelcastPayload.Command((Command) o));
+ } else if (o.getClass().isArray()) {
+ this.topic.publish(new HazelcastPayload.Bytes((byte[]) o));
+ }
+ if (debugInfo != null) {
+ this.logDebugAfterPublish(debugInfo, "");
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void closeInternal() throws Exception {
+ this.topic.destroy();
+ }
+
+ /**
+ * Receives any published message containing hz payload.
+ * @param message the message to process.
+ */
+ @Override
+ public void receiveMessage(ClusterMessage message) {
+ HazelcastPayload payload = message.getPayload();
+ if (!topic.hasPublished(payload)) {
+ HazelcastTopicStorage.getInstance().process(
+ () -> {
+ try {
+ this.processReceivedObject(payload.getCommand(this.rcm), payload.getId().toString());
+ } catch (Exception e) {
+ this.failDeserializeMessage(payload.getId().toString(), e);
+ }
+ }
+ );
+ }
+ }
+}
diff --git a/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastTopicStorage.java b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastTopicStorage.java
new file mode 100644
index 00000000000..5866ae4b7a3
--- /dev/null
+++ b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/HazelcastTopicStorage.java
@@ -0,0 +1,198 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2016-2018 Payara Foundation and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://github.com/payara/Payara/blob/master/LICENSE.txt
+ * See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * The Payara Foundation designates this particular file as subject to the "Classpath"
+ * exception as provided by the Payara Foundation in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+package fish.payara.persistence.eclipselink.cache.coordination;
+
+import fish.payara.nucleus.eventbus.ClusterMessage;
+import fish.payara.nucleus.eventbus.EventBus;
+import fish.payara.nucleus.eventbus.MessageReceiver;
+import fish.payara.nucleus.events.HazelcastEvents;
+import fish.payara.nucleus.executorservice.PayaraExecutorService;
+import org.glassfish.api.StartupRunLevel;
+import org.glassfish.api.event.EventListener;
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.api.event.Events;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.jvnet.hk2.annotations.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Future;
+
+/**
+ * Represents a possibility to delay {@link MessageReceiver} registration.
+ *
+ * @author Sven Diedrichsen
+ */
+@Service(name = "hazelcast-topic-storage")
+@RunLevel(StartupRunLevel.VAL)
+public class HazelcastTopicStorage implements EventListener {
+
+ /**
+ * The singleton instance of the storage.
+ */
+ private static HazelcastTopicStorage storage;
+ /**
+ * The message listener cache.
+ */
+ private final Map messageReceiver = new ConcurrentHashMap<>();
+ /**
+ * Event bus to propagate cache coordination messages over.
+ */
+ @Inject
+ private EventBus eventBus;
+ /**
+ * Executor to process incoming messages.
+ */
+ @Inject
+ private PayaraExecutorService executorService;
+ /**
+ * System-Events interface.
+ */
+ @Inject
+ private Events events;
+
+ @PostConstruct
+ public void postConstruct() {
+ storage = this;
+ this.events.register(this);
+ }
+
+ @PreDestroy
+ public void preDestroy() {
+ storage = null;
+ this.events.unregister(this);
+ }
+
+ /**
+ * Returns the singleton instance of this storage.
+ * @return Singleton storage instance.
+ */
+ public static HazelcastTopicStorage getInstance() {
+ return storage;
+ }
+
+ @Override
+ public void event(Event event) {
+ if (event.is(EventTypes.SERVER_SHUTDOWN)) {
+ clearMessageReceivers();
+ } else if(event.is(HazelcastEvents.HAZELCAST_SHUTDOWN_STARTED)) {
+ unregisterRegisteredReceivers();
+ } else if(event.is(HazelcastEvents.HAZELCAST_BOOTSTRAP_COMPLETE)) {
+ registerUnregisteredReceivers();
+ }
+ }
+
+ /**
+ * Registers all yet unregistered {@link MessageReceiver}.
+ */
+ private void registerUnregisteredReceivers() {
+ messageReceiver.values().stream()
+ .filter(mapping -> !mapping.isRegistered())
+ .forEach(mapping -> mapping.setRegistered(
+ eventBus.addMessageReceiver(mapping.getTopic(), mapping.getMessageReceiver())
+ ));
+ }
+
+ /**
+ * Unregisters all registered {@link MessageReceiver}.
+ */
+ private void unregisterRegisteredReceivers() {
+ messageReceiver.values().stream()
+ .filter(ReceiverMapping::isRegistered)
+ .forEach(mapping -> {
+ eventBus.removeMessageReceiver(mapping.getTopic(), mapping.getMessageReceiver());
+ mapping.setRegistered(false);
+ });
+ }
+
+ /**
+ * Removing all listeners.
+ */
+ private void clearMessageReceivers() {
+ messageReceiver.clear();
+ }
+
+ /**
+ * Processes the submitted work asynchronously.
+ *
+ * @param work The work to process.
+ * @return The {@link Future} representing a handle for the processing.
+ */
+ Future> process(final Runnable work) {
+ return executorService.submit(work);
+ }
+
+ /**
+ * Tries to register the message listener with the provided topic by its name.
+ * @param topic The name of the topic to register the listener with.
+ * @param receiver The receiver to register
+ * @return The internal id for the registered listener usable for removing the listener.
+ */
+ String registerMessageReceiver(String topic, MessageReceiver receiver) {
+ ReceiverMapping receiverMapping = new ReceiverMapping(topic, receiver);
+ receiverMapping.setRegistered(eventBus.addMessageReceiver(topic, receiver));
+ messageReceiver.put(receiverMapping.getInternalId(), receiverMapping);
+ return receiverMapping.getInternalId();
+ }
+
+ /**
+ * Unregisters the listener identified by its internal id for the provided topic.
+ * @param internalId The internal id identifying the listener.
+ */
+ void removeMessageReceiver(String internalId) {
+ ReceiverMapping removedReceiver = messageReceiver.remove(internalId);
+ if (removedReceiver != null) {
+ eventBus.removeMessageReceiver(removedReceiver.getTopic(), removedReceiver.getMessageReceiver());
+ }
+ }
+
+ /**
+ * Publishes the {@link HazelcastPayload} at the topic.
+ * @param topic The name of the topic to publish the payload.
+ * @param payload The payload to publish.
+ */
+ void publish(String topic, HazelcastPayload payload) {
+ eventBus.publish(topic, new ClusterMessage<>(payload));
+ }
+
+}
diff --git a/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/ReceiverMapping.java b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/ReceiverMapping.java
new file mode 100644
index 00000000000..94fd467718b
--- /dev/null
+++ b/appserver/payara-appserver-modules/hazelcast-eclipselink-coordination/src/main/java/fish/payara/persistence/eclipselink/cache/coordination/ReceiverMapping.java
@@ -0,0 +1,97 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2016-2018 Payara Foundation and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://github.com/payara/Payara/blob/master/LICENSE.txt
+ * See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * The Payara Foundation designates this particular file as subject to the "Classpath"
+ * exception as provided by the Payara Foundation in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+package fish.payara.persistence.eclipselink.cache.coordination;
+
+import fish.payara.nucleus.eventbus.MessageReceiver;
+
+import java.util.UUID;
+
+/**
+ * Represents an indirection for hazelcast based
+ * topic receiver registration.
+ *
+ * @author Sven Diedrichsen
+ */
+class ReceiverMapping {
+
+ /**
+ * The internal id.
+ */
+ private final String internalId;
+ /**
+ * the topic name to register a listener for.
+ */
+ private final String topic;
+ /**
+ * The hazelcast message receiver has been registered.
+ */
+ private boolean registered = false;
+ /**
+ * The message receiver.
+ */
+ private final MessageReceiver messageReceiver;
+
+ ReceiverMapping(String topic, MessageReceiver messageReceiver) {
+ this.topic = topic;
+ this.messageReceiver = messageReceiver;
+ this.internalId = UUID.randomUUID().toString();
+ }
+
+ boolean isRegistered() {
+ return registered;
+ }
+
+ String getInternalId() {
+ return internalId;
+ }
+
+ void setRegistered(boolean registered) {
+ this.registered = registered;
+ }
+
+ String getTopic() {
+ return topic;
+ }
+
+ MessageReceiver getMessageReceiver() {
+ return this.messageReceiver;
+ }
+
+}
diff --git a/appserver/payara-appserver-modules/pom.xml b/appserver/payara-appserver-modules/pom.xml
index 6006c96237f..f84d7057ec4 100644
--- a/appserver/payara-appserver-modules/pom.xml
+++ b/appserver/payara-appserver-modules/pom.xml
@@ -53,6 +53,7 @@
payara-jsr107
hazelcast-ejb-timer
+ hazelcast-eclipselink-coordination
requesttracing-api
jmx-monitoring-service
payara-micro-service
@@ -72,7 +73,7 @@
rest-monitoring
cdi-auth-roles
-
+
jdk8