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

com.liferay.portal.kernel.resiliency.spi.remote.RemoteSPI Maven / Gradle / Ivy

There is a newer version: 7.4.3.112-ga112
Show newest version
/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * 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.
 */

package com.liferay.portal.kernel.resiliency.spi.remote;

import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.nio.intraband.RegistrationReference;
import com.liferay.portal.kernel.nio.intraband.rpc.IntrabandRPCUtil;
import com.liferay.portal.kernel.nio.intraband.welder.Welder;
import com.liferay.portal.kernel.nio.intraband.welder.WelderFactoryUtil;
import com.liferay.portal.kernel.process.ProcessCallable;
import com.liferay.portal.kernel.process.ProcessException;
import com.liferay.portal.kernel.process.local.LocalProcessLauncher;
import com.liferay.portal.kernel.resiliency.mpi.MPI;
import com.liferay.portal.kernel.resiliency.mpi.MPIHelperUtil;
import com.liferay.portal.kernel.resiliency.spi.SPI;
import com.liferay.portal.kernel.resiliency.spi.SPIConfiguration;
import com.liferay.portal.kernel.resiliency.spi.agent.SPIAgent;
import com.liferay.portal.kernel.resiliency.spi.agent.SPIAgentFactoryUtil;
import com.liferay.portal.kernel.resiliency.spi.provider.SPISynchronousQueueUtil;
import com.liferay.portal.kernel.util.PropsKeys;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

import java.util.UUID;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * @author Shuyang Zhou
 */
public abstract class RemoteSPI implements ProcessCallable, Remote, SPI {

	public RemoteSPI(SPIConfiguration spiConfiguration) {
		this.spiConfiguration = spiConfiguration;

		mpi = MPIHelperUtil.getMPI();

		UUID uuidObject = UUID.randomUUID();

		uuid = uuidObject.toString();

		welder = WelderFactoryUtil.createWelder();
	}

	@Override
	public SPI call() throws ProcessException {
		try {
			SPIShutdownHook spiShutdownHook = new SPIShutdownHook();

			LocalProcessLauncher.ProcessContext.attach(
				spiConfiguration.getSPIId(), spiConfiguration.getPingInterval(),
				spiShutdownHook);

			Runtime runtime = Runtime.getRuntime();

			runtime.addShutdownHook(spiShutdownHook);

			SPI spi = (SPI)UnicastRemoteObject.exportObject(this, 0);

			RegisterCallback registerCallback = new RegisterCallback(uuid, spi);

			LocalProcessLauncher.ProcessContext.writeProcessCallable(
				registerCallback);

			registrationReference = welder.weld(MPIHelperUtil.getIntraband());

			ConcurrentMap attributes =
				LocalProcessLauncher.ProcessContext.getAttributes();

			attributes.put(SPI.SPI_INSTANCE_PUBLICATION_KEY, this);

			return spi;
		}
		catch (RemoteException re) {
			throw new ProcessException("Failed to export SPI as RMI stub", re);
		}
		catch (IOException ioe) {
			throw new ProcessException(ioe);
		}
	}

	@Override
	public void destroy() throws RemoteException {
		try {
			doDestroy();

			if (countDownLatch != null) {
				countDownLatch.countDown();
			}
		}
		finally {
			UnicastRemoteObject.unexportObject(RemoteSPI.this, true);
		}
	}

	@Override
	public MPI getMPI() {
		return mpi;
	}

	@Override
	public RegistrationReference getRegistrationReference() {
		return registrationReference;
	}

	@Override
	public SPIAgent getSPIAgent() {
		if (spiAgent == null) {
			spiAgent = SPIAgentFactoryUtil.createSPIAgent(
				spiConfiguration, registrationReference);
		}

		return spiAgent;
	}

	@Override
	public SPIConfiguration getSPIConfiguration() {
		return spiConfiguration;
	}

	public String getUUID() {
		return uuid;
	}

	public Welder getWelder() {
		return welder;
	}

	@Override
	public boolean isAlive() {
		return true;
	}

	protected abstract void doDestroy() throws RemoteException;

	protected transient CountDownLatch countDownLatch;
	protected final MPI mpi;
	protected RegistrationReference registrationReference;
	protected transient volatile SPIAgent spiAgent;
	protected final SPIConfiguration spiConfiguration;
	protected final String uuid;
	protected final Welder welder;

	protected static class RegisterCallback implements ProcessCallable {

		public RegisterCallback(String spiUUID, SPI spi) {
			_spiUUID = spiUUID;
			_spi = spi;
		}

		@Override
		public SPI call() throws ProcessException {
			try {
				SPISynchronousQueueUtil.notifySynchronousQueue(_spiUUID, _spi);
			}
			catch (InterruptedException ie) {
				throw new ProcessException(ie);
			}

			return _spi;
		}

		private static final long serialVersionUID = 1L;

		private final SPI _spi;
		private final String _spiUUID;

	}

	protected static class UnregisterSPIProcessCallable
		implements ProcessCallable {

		public UnregisterSPIProcessCallable(
			String spiProviderName, String spiId) {

			_spiProviderName = spiProviderName;
			_spiId = spiId;
		}

		@Override
		public Boolean call() {
			SPI spi = MPIHelperUtil.getSPI(_spiProviderName, _spiId);

			if (spi != null) {
				return MPIHelperUtil.unregisterSPI(spi);
			}

			return false;
		}

		private static final long serialVersionUID = 1L;

		private final String _spiId;
		private final String _spiProviderName;

	}

	protected class SPIShutdownHook
		extends Thread implements LocalProcessLauncher.ShutdownHook {

		public SPIShutdownHook() {
			setDaemon(true);
			setName(SPIShutdownHook.class.getSimpleName());
		}

		@Override
		public void run() {
			if (countDownLatch.getCount() == 0) {
				return;
			}

			boolean unregistered = false;

			try {
				Future future = IntrabandRPCUtil.execute(
					registrationReference,
					new UnregisterSPIProcessCallable(
						getSPIProviderName(), spiConfiguration.getSPIId()));

				unregistered = future.get();
			}
			catch (Exception e) {
				if (_log.isWarnEnabled()) {
					_log.warn("Unable to unregister SPI from MPI", e);
				}
			}

			if (unregistered || !_waitForMPI()) {
				_shutdown();
			}
		}

		@Override
		public boolean shutdown(int shutdownCode, Throwable shutdownThrowable) {
			Runtime runtime = Runtime.getRuntime();

			runtime.removeShutdownHook(this);

			_shutdown();

			return true;
		}

		private void _shutdown() {
			try {
				RemoteSPI.this.stop();
			}
			catch (RemoteException re) {
				_log.error("Unable to stop SPI", re);
			}

			try {
				RemoteSPI.this.destroy();
			}
			catch (RemoteException re) {
				_log.error("Unable to destroy SPI", re);
			}
		}

		private boolean _waitForMPI() {
			if (_log.isInfoEnabled()) {
				_log.info(
					"Wait up to " + spiConfiguration.getShutdownTimeout() +
						" ms for MPI shutdown request");
			}

			try {
				if (countDownLatch.await(
						spiConfiguration.getShutdownTimeout(),
						TimeUnit.MILLISECONDS)) {

					if (_log.isInfoEnabled()) {
						_log.info("MPI shutdown request received");
					}

					return true;
				}
			}
			catch (InterruptedException ie) {
			}

			if (_log.isInfoEnabled()) {
				_log.info("Proceed with SPI shutdown");
			}

			return false;
		}

	}

	private void readObject(ObjectInputStream objectInputStream)
		throws ClassNotFoundException, IOException {

		objectInputStream.defaultReadObject();

		System.setProperty(
			PropsKeys.INTRABAND_IMPL, objectInputStream.readUTF());
		System.setProperty(
			PropsKeys.INTRABAND_TIMEOUT_DEFAULT, objectInputStream.readUTF());
		System.setProperty(
			PropsKeys.INTRABAND_WELDER_IMPL, objectInputStream.readUTF());
		System.setProperty(
			"portal:" + PropsKeys.LIFERAY_HOME, objectInputStream.readUTF());

		// Disable auto deploy

		System.setProperty("portal:" + PropsKeys.AUTO_DEPLOY_ENABLED, "false");

		// Disable cluster link

		System.setProperty("portal:" + PropsKeys.CLUSTER_LINK_ENABLED, "false");

		// Disable dependency management

		System.setProperty(
			"portal:" + PropsKeys.HOT_DEPLOY_DEPENDENCY_MANAGEMENT_ENABLED,
			"false");

		// Log4j log file postfix

		System.setProperty("spi.id", "-" + spiConfiguration.getSPIId());

		countDownLatch = new CountDownLatch(1);
	}

	private void writeObject(ObjectOutputStream objectOutputStream)
		throws IOException {

		objectOutputStream.defaultWriteObject();

		objectOutputStream.writeUTF(
			System.getProperty(PropsKeys.INTRABAND_IMPL));
		objectOutputStream.writeUTF(
			System.getProperty(PropsKeys.INTRABAND_TIMEOUT_DEFAULT));
		objectOutputStream.writeUTF(
			System.getProperty(PropsKeys.INTRABAND_WELDER_IMPL));
		objectOutputStream.writeUTF(System.getProperty(PropsKeys.LIFERAY_HOME));
	}

	private static final Log _log = LogFactoryUtil.getLog(RemoteSPI.class);

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy