blob: d0e27e3f456f7599bf22bbf8f391cf4c01bf2ae8 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 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.sessions.coordination.rmi;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.rmi.Naming;
import java.rmi.NoSuchObjectException;
import java.rmi.server.UnicastRemoteObject;
import javax.naming.Context;
import org.eclipse.persistence.exceptions.RemoteCommandManagerException;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.sessions.coordination.RemoteConnection;
import org.eclipse.persistence.internal.sessions.coordination.rmi.RMIRemoteCommandConnection;
import org.eclipse.persistence.internal.sessions.coordination.rmi.RMIRemoteCommandConnectionImpl;
import org.eclipse.persistence.internal.sessions.coordination.rmi.RMIRemoteConnection;
import org.eclipse.persistence.sessions.coordination.RemoteCommandManager;
import org.eclipse.persistence.sessions.coordination.ServiceId;
import org.eclipse.persistence.sessions.coordination.TransportManager;
/**
* <p>
* <b>Purpose</b>: Provide an RMI transport implementation for RCM.
* </p><p>
* <b>Description</b>: This class manages the RMI remote connections to other
* RCM service instances and posts the local RMI connection to this service instance
* in a name service so that other RCM service instances can connect to it.
* </p>
* @author Steven Vo
* @since OracleAS TopLink 10<i>g</i> (9.0.4)
*/
public class RMITransportManager extends TransportManager {
private Method narrow;
private Constructor constructor;
public RMITransportManager(RemoteCommandManager rcm) {
this.rcm = rcm;
this.initialize();
}
/**
* INTERNAL:
* Create and return an RMI remote connection to the specified service
*/
@Override
public RemoteConnection createConnection(ServiceId connectionServiceId) {
RemoteConnection connection = null;
if (namingServiceType == REGISTRY_NAMING_SERVICE) {
connection = createConnectionFromRegistry(connectionServiceId.getId(), connectionServiceId.getURL());
} else if (namingServiceType == JNDI_NAMING_SERVICE) {
connection = createConnectionFromJNDI(connectionServiceId.getId(), connectionServiceId.getURL());
}
if (connection != null) {
connection.setServiceId(connectionServiceId);
}
return connection;
}
/**
* INTERNAL:
* Look the specified remote object up in JNDI and return a Connection to it.
*/
protected RemoteConnection createConnectionFromJNDI(String remoteObjectIdentifier, String hostURL) {
Object[] args = { remoteObjectIdentifier, hostURL };
rcm.logDebug("looking_up_remote_conn_in_jndi", args);
try {
Context context = getRemoteHostContext(hostURL);
//Use JNDI lookup(), rather than the RMI version,
//AND replace the Java remote interface cast with a call to javax.rmi.PortableRemoteObject.narrow():
if (narrow != null) {
return new RMIRemoteConnection((RMIRemoteCommandConnection) narrow.invoke(
null, context.lookup(remoteObjectIdentifier), RMIRemoteCommandConnection.class));
} else {
return new RMIRemoteConnection((RMIRemoteCommandConnection)context.lookup(remoteObjectIdentifier));
}
} catch (Exception e) {
try {
rcm.handleException(RemoteCommandManagerException.errorLookingUpRemoteConnection(remoteObjectIdentifier, hostURL, e));
} catch (Exception ex2) {
// Must catch this exception and log a debug message
rcm.logDebug("unable_to_look_up_remote_conn_in_jndi", args);
}
}
return null;
}
/**
* INTERNAL:
* Look the specified remote object up in the RMIRegistry and return a Connection to it.
*/
protected RemoteConnection createConnectionFromRegistry(String remoteObjectIdentifier, String hostURL) {
String formattedUrl = formatURLforRegistry(hostURL, remoteObjectIdentifier);
Object[] args = { formattedUrl };
rcm.logDebug("looking_up_remote_conn_in_registry", args);
try {
return new RMIRemoteConnection((RMIRemoteCommandConnection)Naming.lookup(formattedUrl));
} catch (Exception e) {
try {
rcm.handleException(RemoteCommandManagerException.errorLookingUpRemoteConnection(remoteObjectIdentifier, hostURL, e));
} catch (Exception ex2) {
// Must catch this exception and log a debug message
rcm.logDebug("unable_to_look_up_remote_conn_in_registry", args);
}
}
return null;
}
/**
* INTERNAL:
* Create the local command connection for this transport in a naming service and
* return it.
*/
@Override
public void createLocalConnection() {
if (namingServiceType == REGISTRY_NAMING_SERVICE) {
createLocalConnectionInRegistry();
} else if (namingServiceType == JNDI_NAMING_SERVICE) {
createLocalConnectionInJNDI();
}
if (localConnection != null) {
localConnection.setServiceId(rcm.getServiceId());
}
}
/**
* INTERNAL:
* Put the local command connection of this transport in JNDI and return it
*/
protected void createLocalConnectionInJNDI() {
try {
// Register the remote connection in JNDI naming service
RMIRemoteCommandConnection remoteConnectionObject;
if (narrow != null) {
if (constructor == null) {
try {
constructor = PrivilegedAccessHelper.getConstructorFor(
Class.forName("org.eclipse.persistence.internal.sessions.coordination.rmi.iiop.RMIRemoteCommandConnectionImpl"),
new Class<?>[] {RemoteCommandManager.class}, false);
} catch (ReflectiveOperationException e) {
throw RemoteCommandManagerException.errorInitCorba("javax.rmi.PortableRemoteObject", e);
}
}
try {
remoteConnectionObject = (RMIRemoteCommandConnection) PrivilegedAccessHelper.invokeConstructor(constructor, new Object[] {rcm});
} catch (ReflectiveOperationException e) {
// TODO Auto-generated catch block
throw RemoteCommandManagerException.errorInitCorba("javax.rmi.PortableRemoteObject", e);
}
} else {
remoteConnectionObject = new RMIRemoteCommandConnectionImpl(rcm);
}
Object[] args = { rcm.getServiceId().getId() };
rcm.logDebug("register_local_connection_in_jndi", args);
getLocalHostContext().rebind(rcm.getServiceId().getId(), remoteConnectionObject);
localConnection = new RMIRemoteConnection(remoteConnectionObject);
} catch (Exception exception) {
rcm.handleException(RemoteCommandManagerException.errorBindingConnection(rcm.getServiceId().toString(), exception));
}
}
/**
* INTERNAL:
* Put the local command connection of this transport in the Registry and return it
*/
protected RemoteConnection createLocalConnectionInRegistry() {
String fullURL = formatURLforRegistry(rcm.getServiceId().getURL(), rcm.getServiceId().getId());
try {
// Register the remote connection in RMI Registry naming service
RMIRemoteCommandConnectionImpl remoteConnectionObject = new RMIRemoteCommandConnectionImpl(rcm);
Object[] args = { fullURL };
rcm.logDebug("register_local_connection_in_registry", args);
Naming.rebind(fullURL, remoteConnectionObject);
localConnection = new RMIRemoteConnection(remoteConnectionObject);
} catch (Exception exception) {
rcm.handleException(RemoteCommandManagerException.errorBindingConnection(fullURL, exception));
}
return localConnection;
}
/**
* INTERNAL:
* Return the context used for looking up in local JNDI.
*/
public Context getLocalHostContext() {
return getContext(getLocalContextProperties());
}
/**
* INTERNAL:
* Format the URL so that it can be used to look up the RMI Registry.
*/
private String formatURLforRegistry(String url, String serviceName) {
if (url == null) {
return null;
}
String fullURL = url;
if ((fullURL.endsWith("/") || fullURL.endsWith("\\"))) {
fullURL = fullURL.substring(0, fullURL.length() - 1);
}
return fullURL + "/" + serviceName;
}
/**
* INTERNAL:
* Return the default local URL for JNDI lookups
*/
public String getDefaultLocalUrl() {
try {
// Look up the local host name and paste it in a default URL
String localHost = InetAddress.getLocalHost().getHostName();
if (narrow != null) {
return DEFAULT_IIOP_URL_PROTOCOL + "::" + localHost + ":" + DEFAULT_IIOP_URL_PORT;
} else {
return DEFAULT_URL_PROTOCOL + "://" + localHost + ":" + DEFAULT_URL_PORT;
}
} catch (IOException exception) {
throw RemoteCommandManagerException.errorGettingHostName(exception);
}
}
/**
* INTERNAL:
* Initialize default properties for RMI.
*/
@Override
public void initialize() {
super.initialize();
// URL is not required when in a cluster, do not default.
//if (rcm.getServiceId().getURL() == null) {
// rcm.getServiceId().setURL(getDefaultLocalUrl());
//}
namingServiceType = DEFAULT_NAMING_SERVICE;
}
/**
* ADVANCED:
* Remove the local connection from remote accesses. The implementation removes the local connection from JNDI or the
* RMI registry, un-exports it from the RMI runtime, and sets it to null.
* This method is invoked internally by EclipseLink when the RCM is shutdown and should not be invoked by user's application.
*/
@Override
public void removeLocalConnection() {
String unbindName = null;
try {
if (namingServiceType == REGISTRY_NAMING_SERVICE) {
unbindName = formatURLforRegistry(rcm.getServiceId().getURL(), rcm.getServiceId().getId());
Naming.unbind(unbindName);
} else if (namingServiceType == JNDI_NAMING_SERVICE) {
unbindName = rcm.getServiceId().getId();
getLocalHostContext().unbind(unbindName);
} else {
return;
}
} catch (Exception exception) {
rcm.handleException(RemoteCommandManagerException.errorUnbindingLocalConnection(unbindName, exception));
} finally {
// unexport the local connection from the RMI runtime
RMIRemoteConnection localConnection = (RMIRemoteConnection)getConnectionToLocalHost();
if (localConnection != null) {
RMIRemoteCommandConnection commandConnection = localConnection.getConnection();
if (commandConnection != null) {
try {
UnicastRemoteObject.unexportObject(commandConnection, true);
} catch (NoSuchObjectException nso) {
// if the object isn't exported, ignore this exception since cleanup is being performed
}
}
this.localConnection = null;
}
}
}
public void setIsRMIOverIIOP(boolean b) {
if (b) {
try {
narrow = PrivilegedAccessHelper.getDeclaredMethod(Class.forName("javax.rmi.PortableRemoteObject"), "narrow", new Class<?>[] {Object.class, Class.class});
} catch (ReflectiveOperationException e) {
// TODO Auto-generated catch block
throw RemoteCommandManagerException.errorInitCorba("javax.rmi.PortableRemoteObject", e);
}
} else {
narrow = null;
}
}
}