All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.sessions.coordination.broadcast.BroadcastRemoteConnection Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*
 * Copyright (c) 1998, 2018 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 from Oracle TopLink
package org.eclipse.persistence.internal.sessions.coordination.broadcast;

import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.sessions.coordination.RemoteConnection;
import org.eclipse.persistence.sessions.coordination.broadcast.BroadcastTransportManager;
import org.eclipse.persistence.sessions.coordination.Command;
import org.eclipse.persistence.sessions.coordination.RemoteCommandManager;
import org.eclipse.persistence.exceptions.CommunicationException;
import org.eclipse.persistence.exceptions.RemoteCommandManagerException;

/**
 * 

* Purpose: Base class extending RemoteConnection for broadcasting RCM protocols: JMS and Oc4jJGroups. *

* Description: Defines lifecycle states and most of the methods, * as well as exception processing and info logging. *

* @author Andrei Ilitchev * @since OracleAS TopLink 11g (11.1.1) */ public abstract class BroadcastRemoteConnection extends RemoteConnection { protected RemoteCommandManager rcm; protected String topicName; // Working state - connection can send and/or receive messages. public static final String STATE_ACTIVE = "ACTIVE"; // close method called but not all resources used by connection are freed yet. // Note that even after close method returns the state still may be CLOSING. public static final String STATE_CLOSING = "CLOSING"; // All resources are freed. public static final String STATE_CLOSED = "CLOSED"; // STATE_ACTIVE -> STATE_CLOSING -> STATE_CLOSED protected String state = STATE_ACTIVE; // Connection information String. protected String displayString; // Array containing a single element - displayString. Used for warnings and debug logging. protected Object[] info; // Array containing a two elements - displayString and an empty String. // Used for debug logging which require messageId in case messageId is null // (so that a new array is not created each time). protected Object[] infoExt; public BroadcastRemoteConnection(RemoteCommandManager rcm) { this.serviceId = rcm.getServiceId(); this.rcm = rcm; this.topicName = ((BroadcastTransportManager)rcm.getTransportManager()).getTopicName(); } /** * INTERNAL: * Publish the remote command. The result of execution is returned. * This method is used only by external (publishing) connection. */ public Object executeCommand(Command command) throws CommunicationException { if (isActive()) { try { return executeCommandInternal(command); } catch (Exception exception) { // Note that there is no need to removeConnection here - it's removed by the calling method: // org.eclipse.persistence.internal.sessions.coordination.CommandPropagator.propagateCommand. // This method catches CommunicationException and processes it in handleCommunicationException method. // The latter method, in case shouldRemoveConnectionOnError==true, removes the connection; // otherwise it wraps the CommunicationException into RemoteCommandManagerException // (with errorCode RemoteCommandManagerException.ERROR_PROPAGATING_COMMAND) // and gives the use a chance to handle it - this is an opportunity for the user to // stop remote command processing. throw CommunicationException.errorSendingMessage(getServiceId().getId(), exception); } } else { rcm.logWarning("broadcast_ignored_command_while_closing_connection", getInfo()); return null; } } /** * INTERNAL: * Publish the remote command. The result of execution is returned. * This method is used only by external (publishing) connection. */ public Object executeCommand(byte[] command) throws CommunicationException { if (isActive()) { try { return executeCommandInternal(command); } catch (Exception exception) { // Note that there is no need to removeConnection here - it's removed by the calling method: // org.eclipse.persistence.internal.sessions.coordination.CommandPropagator.propagateCommand. // This method catches CommunicationException and processes it in handleCommunicationException method. // The latter method, in case shouldRemoveConnectionOnError==true, removes the connection; // otherwise it wraps the CommunicationException into RemoteCommandManagerException // (with errorCode RemoteCommandManagerException.ERROR_PROPAGATING_COMMAND) // and gives the use a chance to handle it - this is an opportunity for the user to // stop remote command processing. throw CommunicationException.errorSendingMessage(getServiceId().getId(), exception); } } else { rcm.logWarning("broadcast_ignored_command_while_closing_connection", getInfo()); return null; } } /** * INTERNAL: * Publish the remote command. The result of execution is returned. * This method is used only by external (publishing) connection. */ protected abstract Object executeCommandInternal(Object command) throws Exception; /** * INTERNAL: * Called from executeCommandInternal to log debugInfo right before sending the message. * Returns array {toString(), messageId }. * In case messageId is null returns getInfoExt() avoiding creation of a new array. */ protected Object[] logDebugBeforePublish(String messageId) { Object[] debugInfo = null; if(messageId == null) { debugInfo = getInfoExt(); } else { debugInfo = new Object[] {toString(), messageId}; } // call logDebugWithoutLevelCheck to avoid the second rcm.shouldLogDebugMessage() check rcm.logDebugWithoutLevelCheck("broadcast_sending_message", debugInfo); return debugInfo; } /** * INTERNAL: * Called from executeCommandInternal to log debugInfo right after sending the message. * Only call this method in case logDebugBeforePublish returned non-null * this is indication that debug logging is enabled. * Pass to this method debugInfo returned by logDebugBeforePublish. * Need to pass messageId only in case it has changed since logDebugBeforePublish: * some broadcasting protocols (JMS) don't generate messageId until the message is published. */ protected void logDebugAfterPublish(Object[] debugInfo, String messageId) { if(messageId != null) { if(debugInfo == getInfoExt()) { // need to create a new debugInfo object - the original is the cached info. debugInfo = new Object[] {toString(), messageId}; } else { // need only update messageId on existing debugInfo debugInfo[3] = messageId; } } // call logDebugWithoutLevelCheck to avoid the second rcm.shouldLogDebugMessage() check rcm.logDebugWithoutLevelCheck("broadcast_sent_message", debugInfo); } /** * INTERNAL: * Called when a message is received to log debugInfo: * { toString(), messageId }. * This method is used by local (listening) connection only. */ protected void logDebugOnReceiveMessage(String messageId) { Object[] debugInfo = null; if(messageId == null) { debugInfo = getInfoExt(); } else { debugInfo = new Object[] {toString(), messageId}; } // call logDebugWithoutLevelCheck to avoid the second rcm.shouldLogDebugMessage() check rcm.logDebugWithoutLevelCheck("broadcast_retreived_message", debugInfo); } /** * INTERNAL: * Process the object extracted from the received message. * Pass to this method messageInfo created by logDebugOnReceiveMessage method. * This method is used by local (listening) connection only. */ protected void processReceivedObject(Object object, String messageId) { Command remoteCommand = null; if (object instanceof Command) { remoteCommand = (Command)object; try { // prevent the processing of messages sent with the same serviceId if (shouldCheckServiceId()) { if (remoteCommand.getServiceId().getId().equals(this.serviceId.getId())) { return; } } if (remoteCommand.getServiceId().getChannel().equals(this.serviceId.getChannel())) { if(rcm.shouldLogDebugMessage()) { Object[] args = { toString(), messageId, remoteCommand.getServiceId().toString(), Helper.getShortClassName(remoteCommand) }; rcm.logDebugWithoutLevelCheck("broadcast_processing_remote_command", args); } rcm.processCommandFromRemoteConnection(remoteCommand); } else { if(rcm.shouldLogWarningMessage()) { Object[] args = { toString(), messageId, remoteCommand.getServiceId().toString(), Helper.getShortClassName(remoteCommand)}; rcm.logWarningWithoutLevelCheck("broadcast_ignore_remote_command_from_different_channel", args); } } } catch (RuntimeException e) { try { rcm.handleException(RemoteCommandManagerException.errorProcessingRemoteCommand(toString(), messageId, remoteCommand.getServiceId().toString(), Helper.getShortClassName(remoteCommand), e)); } catch (RuntimeException ex) { // User had a chance to handle the exception. // The method is called by a listener thread - no one could catch this exception. } } } else if (object == null) { Object[] args = { toString(), messageId}; rcm.logWarning("broadcast_remote_command_is_null", args); } else { if(rcm.shouldLogWarningMessage()) { String className = object.getClass().getName(); Object[] args = { toString(), messageId, className }; rcm.logWarningWithoutLevelCheck("broadcast_remote_command_wrong_type", args); } } } /** * INTERNAL: * Call this message in case there is failure to extract the object * (to be passed to processReceivedObject) from the message. * Pass to this method debugInfo created by logDebugOnReceiveMessage method. * This method is used by local (listening) connection only. */ protected void failDeserializeMessage(String messageId, Exception exception) { try { rcm.handleException(RemoteCommandManagerException.errorDeserializeRemoteCommand(toString(), messageId, exception)); } catch (Exception ex) { // User had a chance to handle the exception. // The method is called by a listener thread - no one could catch this exception. } } /** * INTERNAL: * This method is called when connection in no longer used and it's resources should be freed. * As soon as this method is called the state is CLOSING. * Usually the state is CLOSED just before the method returns, * but there are some special cases (see comment to areAllResourcesFreedOnClose method) * when the state is still CLOSING after the method returns. */ public void close() { synchronized(this) { if(isClosing()) { rcm.logWarning("broadcast_connection_already_closing", getInfo()); return; } else if(isClosed()) { rcm.logWarning("broadcast_connection_already_closed", getInfo()); return; } else { state = STATE_CLOSING; } } try { rcm.logDebug("broadcast_closing_connection", getInfo()); closeInternal(); } catch (Exception exception) { Object[] args = { toString(), exception }; rcm.logWarning("broadcast_exception_thrown_when_attempting_to_close_connection", args); } finally { if(areAllResourcesFreedOnClose()) { rcm.logDebug("broadcast_connection_closed", getInfo()); state = STATE_CLOSED; } } } /** * INTERNAL: * State of the connection. */ public String getState() { return state; } /** * INTERNAL: * Connection is open for business. */ public boolean isActive() { return state == STATE_ACTIVE; } /** * INTERNAL: * close method has been called. */ public boolean isClosing() { return state == STATE_CLOSING; } /** * INTERNAL: * Connection is closed - all resources were freed. */ public boolean isClosed() { return state == STATE_CLOSED; } /** * INTERNAL: * This method is called by close method. * This method usually * (but not always see comment to areAllResourcesFreedOnClose method) * frees all the resources. */ protected abstract void closeInternal() throws Exception; /** * INTERNAL: */ public String getTopicName() { return topicName; } /** * INTERNAL: */ protected Object[] getInfo() { if(info == null) { info = new Object[] {toString()}; } return info; } /** * INTERNAL: */ protected Object[] getInfoExt() { if(infoExt == null) { infoExt = new Object[] {toString(), ""}; } return infoExt; } /** * INTERNAL: * Indicates whether all the resources used by connection are freed after close method returns. * Usually that's the case. However in case of local (listening) JMSTopicRemoteConnection * close merely indicates to the listening thread that it should free TopicConnection and exit. * Note that it may take a while: the listening thread waits until subscriber.receive method either * returns a message or throws an exception. */ protected boolean areAllResourcesFreedOnClose() { return true; } /** * INTERNAL: */ public String toString() { if(displayString == null) { createDisplayString(); } return displayString; } /** * INTERNAL: */ protected void createDisplayString() { this.displayString = Helper.getShortClassName(this) + "[" + serviceId.toString() + ", topic " + topicName +"]"; } /** * INTERNAL: * Return whether a BroadcastConnection should check a ServiceId against its * own ServiceId to avoid the processing of Commands with the same ServiceId. * @return boolean */ protected boolean shouldCheckServiceId() { return false; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy