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