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

org.tentackle.dbms.rmi.RemoteDbConnectionImpl Maven / Gradle / Ivy

/*
 * Tentackle - https://tentackle.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.tentackle.dbms.rmi;

import org.tentackle.common.ExceptionHelper;
import org.tentackle.io.ServerSocketConfigurator;
import org.tentackle.io.ServerSocketConfiguratorHolder;
import org.tentackle.log.Logger;
import org.tentackle.session.SessionInfo;
import org.tentackle.session.VersionIncompatibleException;

import java.io.Serial;
import java.net.BindException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.UnicastRemoteObject;

/**
 * Server side RMI-connection implementation.
 * 

* Overview of what happens in a Tentackle RMI application rmiServer: *

    *
  • client gets a reference to a RemoteDbConnection
  • *
  • client invokes login() on the connection and gets a reference to a RemoteDbSession.
  • *
  • each session runs in its own thread (rmiServer and client) and the rmiServer session gets its own Db.
  • *
  • all further client requests work through the session object and the remote delegates created within the session
  • *
  • the client invokes logout() to close the session and Db.
  • *
  • in case the client terminates abnormally (without invoking logout()) a timeout runs logout() via its cleanable.
  • *
* @author harald */ public abstract class RemoteDbConnectionImpl extends RemoteServerObject implements RemoteDbConnection { @Serial private static final long serialVersionUID = 1L; private static final Logger LOGGER = Logger.get(RemoteDbConnectionImpl.class); private final transient RmiServer rmiServer; // the rmiServer /** * Creates a connection.
* * @param rmiServer the RMI-server * @param port the tcp-port, 0 = system default * @param csf the client socket factory, null = system default * @param ssf the rmiServer socket factory, null = system default * @throws RemoteException if failed to export object * @see RmiServer */ public RemoteDbConnectionImpl(RmiServer rmiServer, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException { super(port, csf, ssf); this.rmiServer = rmiServer; } /** * Gets the RMI-server. * * @return the RMI server */ public RmiServer getRmiServer() { return rmiServer; } /** * Checks the client's version. *

* The default implementation does nothing. * It is invoked only for remote connections. *

* Throws {@link VersionIncompatibleException} if versions are not compatible. * * @param clientVersion the client version */ public void checkClientVersion(String clientVersion) { // default is ok } /** * Creates the session.
* Needs to be implemented by the application. * * @param clientInfo the client info (login info) * @return the created session * @throws RemoteException if creation failed */ public abstract RemoteDbSession createSession(SessionInfo clientInfo) throws RemoteException; /** * Exports the given remote object. *

* Notice that the delegate must not extend {@link UnicastRemoteObject}! * * @param remoteObject the object to export * @param port the port to export the object on, 0 if auto * @param csf the client-side socket factory for making calls to the remote object, null if system default * @param ssf the rmiServer-side socket factory for receiving remote calls, null if system default * @return the effective port, 0 if system default * @throws RemoteException if export failed */ public int exportRemoteObject(Remote remoteObject, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException { if (remoteObject instanceof UnicastRemoteObject) { throw new RemoteException("delegate " + remoteObject.getClass().getName() + " must not extend UnicastRemoteObject!"); } int portRange = 0; if (ssf instanceof ServerSocketConfiguratorHolder sscd) { ServerSocketConfigurator ssc = sscd.getSocketConfigurator(); if (ssc != null) { portRange = ssc.getPortRange(); if (ssc.getPort() > 0) { port = ssc.getPort(); } } } if (portRange < 1 || port == 0) { portRange = 1; } RemoteException lastEx = null; int effectivePort = -1; int maxPort = port + portRange; for (int p = port; p < maxPort; p++) { try { LOGGER.fine("exporting at port={0}, csf={1}, ssf={2}: {3}", p, csf, ssf, remoteObject); UnicastRemoteObject.exportObject(remoteObject, p, csf, ssf); effectivePort = p; break; } catch (RemoteException ex) { if (ExceptionHelper.extractException(BindException.class, true, ex) == null) { throw ex; // some other exception } // BindException: try next port lastEx = ex; } } if (effectivePort == -1 && lastEx != null) { // export failed for all ports in range throw lastEx; } return effectivePort; } /** * Un-exports the given remote object. * * @param remoteObject the object to un-export * @throws RemoteException if the remote object is not currently exported */ public void unexportRemoteObject(Remote remoteObject) throws RemoteException { UnicastRemoteObject.unexportObject(remoteObject, true); LOGGER.fine("{0} un-exported", remoteObject); } // ------------------ implements RemoteDbConnection ----------------- @Override public String getServerVersion() throws RemoteException { return null; } @Override public RemoteDbSession login(SessionInfo clientInfo) throws RemoteException { // check client compatibility checkClientVersion(clientInfo.getClientVersion()); // create the session RemoteDbSession session = createSession(clientInfo); // export the session if (session instanceof Exportable) { ((Exportable) session).exportMe(); } return session; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy