| /* |
| * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation |
| package org.eclipse.persistence.internal.sessions.coordination.jgroups; |
| |
| import org.eclipse.persistence.internal.helper.Helper; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.internal.sessions.coordination.broadcast.BroadcastRemoteConnection; |
| import org.eclipse.persistence.sessions.coordination.RemoteCommandManager; |
| import org.eclipse.persistence.sessions.serializers.Serializer; |
| import org.jgroups.JChannel; |
| import org.jgroups.Message; |
| import org.jgroups.ReceiverAdapter; |
| |
| /** |
| * <p> |
| * <b>Purpose</b>: Define the implementation of the abstract RemoteConnection for JGroups. |
| * <p> |
| * <b>Description</b>: Executing commands implementation of RemoteConnection is done via JGroups JChannel. |
| * |
| * @author James Sutherland |
| * @since EclipseLink 2.5 |
| */ |
| public class JGroupsRemoteConnection extends BroadcastRemoteConnection { |
| |
| private static final long serialVersionUID = -2285543305296840902L; |
| |
| protected transient JChannel channel; |
| // indicates whether it's a local connection. |
| protected boolean isLocal; |
| |
| /** |
| * INTERNAL: |
| * Constructor creating either a local or external connection. |
| */ |
| public JGroupsRemoteConnection(RemoteCommandManager rcm, JChannel channel, boolean isLocalConnectionBeingCreated) { |
| super(rcm); |
| this.channel = channel; |
| this.isLocal = isLocalConnectionBeingCreated; |
| rcm.logDebug("creating_broadcast_connection", getInfo()); |
| try { |
| if (isLocalConnectionBeingCreated) { |
| // it's a local connection |
| this.channel.setReceiver(new ReceiverAdapter() { |
| @Override |
| public void receive(Message message) { |
| onMessage(message); |
| } |
| }); |
| rcm.logDebug("broadcast_connection_created", getInfo()); |
| } |
| } catch (RuntimeException ex) { |
| rcm.logDebug("failed_to_create_broadcast_connection", getInfo()); |
| close(); |
| throw ex; |
| } |
| } |
| |
| /** |
| * Creates local connections. |
| */ |
| public JGroupsRemoteConnection(RemoteCommandManager rcm){ |
| super(rcm); |
| this.isLocal = true; |
| } |
| |
| /** |
| * INTERNAL: |
| * Indicates whether connection is local (subscriber) |
| * or external (publisher). |
| */ |
| public boolean isLocal() { |
| return isLocal; |
| } |
| |
| /** |
| * INTERNAL: |
| * Execute the remote command. The result of execution is returned. |
| * This method is used only by external (publishing) connection. |
| */ |
| @Override |
| protected Object executeCommandInternal(Object command) throws Exception { |
| Message message = null; |
| if (command instanceof byte[]) { |
| message = new Message(null, (byte[])command); |
| } else { |
| message = new Message(null, command); |
| } |
| |
| Object[] debugInfo = null; |
| if(this.rcm.shouldLogDebugMessage()) { |
| debugInfo = logDebugBeforePublish(null); |
| } |
| |
| this.channel.send(message); |
| |
| // debug logging is on |
| if (debugInfo != null) { |
| logDebugAfterPublish(debugInfo, null); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Process received JGroups message. |
| * This method is used only by local (listening) connection. |
| */ |
| public void onMessage(Message message) { |
| String messageId = ""; |
| if (rcm.shouldLogDebugMessage()) { |
| logDebugOnReceiveMessage(null); |
| logDebugMessage(message); |
| } |
| |
| Object object = null; |
| try { |
| Serializer serializer = this.rcm.getSerializer(); |
| if (serializer != null) { |
| object = serializer.deserialize(message.getBuffer(), (AbstractSession)this.rcm.getCommandProcessor()); |
| } else { |
| object = message.getObject(); |
| } |
| } catch (Exception exception) { |
| failDeserializeMessage(null, exception); |
| return; |
| } |
| |
| processReceivedObject(object, messageId); |
| } |
| |
| /** |
| * INTERNAL: |
| * Indicates whether all the resources used by connection are freed after close method returns. |
| */ |
| @Override |
| protected boolean areAllResourcesFreedOnClose() { |
| return !isLocal(); |
| } |
| |
| /** |
| * INTERNAL: |
| * This method is called by close method. |
| */ |
| @Override |
| protected void closeInternal() { |
| if (areAllResourcesFreedOnClose() && this.channel != null) { |
| this.channel.close(); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| protected String logDebugMessage(Message message) { |
| Object[] args = { this.channel.getName() }; |
| // call logDebugWithoutLevelCheck to avoid the second rcm.shouldLogDebugMessage() check |
| rcm.logDebugWithoutLevelCheck("retreived_remote_message_from_jgroup_channel", args); |
| return this.channel.getName(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Used for debug logging |
| */ |
| @Override |
| protected void createDisplayString() { |
| this.displayString = Helper.getShortClassName(this) + "[" + serviceId.toString() + "]"; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return whether a BroadcastConnection should check a ServiceId against its |
| * own ServiceId to avoid the processing of Commands with the same ServiceId. |
| * Not required for JGroups. |
| */ |
| @Override |
| protected boolean shouldCheckServiceId() { |
| return false; |
| } |
| } |