Java tutorial
/* * R Service Bus * * Copyright (c) Copyright of Open Analytics NV, 2010-2015 * * =========================================================================== * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.openanalytics.rsb.rservi; import java.io.InputStream; import java.io.OutputStream; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; import javax.management.ObjectName; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.pool.BaseKeyedPoolableObjectFactory; import org.apache.commons.pool.KeyedObjectPool; import org.apache.commons.pool.KeyedPoolableObjectFactory; import org.apache.commons.pool.impl.GenericKeyedObjectPool.Config; import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.springframework.jmx.export.MBeanExportOperations; import org.springframework.stereotype.Component; import de.walware.rj.data.RObject; import de.walware.rj.data.RReference; import de.walware.rj.servi.RServi; import de.walware.rj.servi.RServiUtil; import de.walware.rj.services.FunctionCall; import de.walware.rj.services.RGraphicCreator; import de.walware.rj.services.RPlatform; import eu.openanalytics.rsb.Constants; import eu.openanalytics.rsb.Util; import eu.openanalytics.rsb.config.Configuration; import eu.openanalytics.rsb.config.Configuration.RServiClientPoolValidationStrategy; /** * Provides RServi connection over RMI. * * @author "OpenAnalytics <rsb.development@openanalytics.eu>" */ @Component public class RmiRServiInstanceProvider implements RServiInstanceProvider { private static class RServiPoolKey { private final String address, clientId; RServiPoolKey(final String address, final String clientId) { this.address = address; this.clientId = clientId; } String getAddress() { return address; } String getClientId() { return clientId; } @Override public String toString() { return ToStringBuilder.reflectionToString(this); } @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } @Override public boolean equals(final Object obj) { return EqualsBuilder.reflectionEquals(this, obj); } } private static class PooledRServiWrapper implements ErrorableRServi { private final KeyedObjectPool<RServiPoolKey, PooledRServiWrapper> rServiPool; private final RServiPoolKey key; private final RServi rServi; private volatile boolean hasError; PooledRServiWrapper(final KeyedObjectPool<RServiPoolKey, PooledRServiWrapper> rServiPool, final RServiPoolKey key, final RServi rServi) { this.rServiPool = rServiPool; this.key = key; this.rServi = rServi; } public boolean isClosed() { return rServi.isClosed(); } public void close() throws CoreException { try { rServiPool.returnObject(key, this); } catch (final Exception e) { LOGGER.error("Failed to return object to pool", e); } } public void destroy() throws CoreException { rServi.close(); } public void resetError() { hasError = false; } public void markError() { hasError = true; } public boolean hasError() { return hasError; } public RPlatform getPlatform() { return rServi.getPlatform(); } public void evalVoid(final String expression, final IProgressMonitor monitor) throws CoreException { rServi.evalVoid(expression, monitor); } public RObject evalData(final String expression, final IProgressMonitor monitor) throws CoreException { return rServi.evalData(expression, monitor); } public RObject evalData(final String expression, final String factoryId, final int options, final int depth, final IProgressMonitor monitor) throws CoreException { return rServi.evalData(expression, factoryId, options, depth, monitor); } public RObject evalData(final RReference reference, final IProgressMonitor monitor) throws CoreException { return rServi.evalData(reference, monitor); } public RObject evalData(final RReference reference, final String factoryId, final int options, final int depth, final IProgressMonitor monitor) throws CoreException { return rServi.evalData(reference, factoryId, options, depth, monitor); } public void assignData(final String expression, final RObject data, final IProgressMonitor monitor) throws CoreException { rServi.assignData(expression, data, monitor); } public void uploadFile(final InputStream in, final long length, final String fileName, final int options, final IProgressMonitor monitor) throws CoreException { rServi.uploadFile(in, length, fileName, options, monitor); } public void downloadFile(final OutputStream out, final String fileName, final int options, final IProgressMonitor monitor) throws CoreException { rServi.downloadFile(out, fileName, options, monitor); } public byte[] downloadFile(final String fileName, final int options, final IProgressMonitor monitor) throws CoreException { return rServi.downloadFile(fileName, options, monitor); } public FunctionCall createFunctionCall(final String name) throws CoreException { return rServi.createFunctionCall(name); } public RGraphicCreator createRGraphicCreator(final int options) throws CoreException { return rServi.createRGraphicCreator(options); } } private final static Log LOGGER = LogFactory.getLog(RmiRServiInstanceProvider.class); @Resource private Configuration configuration; @Resource private MBeanExportOperations mbeanExportOperations; private KeyedObjectPool<RServiPoolKey, PooledRServiWrapper> rServiPool; @PostConstruct public void initialize() { final Config config = configuration.getRServiClientPoolConfig(); if (config != null) { configurePool(config); initializeRServiClientPool(config); registerRServiClientPoolMBean(); } } private void configurePool(final Config config) { final RServiClientPoolValidationStrategy rServiClientPoolValidationStrategy = configuration .getRServiClientPoolValidationStrategy(); if (rServiClientPoolValidationStrategy != null) { rServiClientPoolValidationStrategy.configurePool(config); } } private void initializeRServiClientPool(final Config config) { final KeyedPoolableObjectFactory<RServiPoolKey, PooledRServiWrapper> factory = new BaseKeyedPoolableObjectFactory<RServiPoolKey, PooledRServiWrapper>() { @Override public PooledRServiWrapper makeObject(final RServiPoolKey key) throws Exception { final RServi rServi = RServiUtil.getRServi(key.getAddress(), key.getClientId()); return new PooledRServiWrapper(rServiPool, key, rServi); } @Override public void destroyObject(final RServiPoolKey key, final PooledRServiWrapper rServi) throws Exception { rServi.destroy(); } @Override public boolean validateObject(final RServiPoolKey key, final PooledRServiWrapper rServi) { if (rServi.isClosed()) { return false; } if (rServi.hasError() || configuration .getRServiClientPoolValidationStrategy() == RServiClientPoolValidationStrategy.FULL) { final boolean responding = Util.isRResponding(rServi); if (rServi.hasError() && LOGGER.isInfoEnabled()) { LOGGER.info(String.format("RServi @ %s has been found %svalid after error", key.getAddress(), responding ? "" : "in")); } if (responding) { rServi.resetError(); } return responding; } else { return true; } } }; rServiPool = new GenericKeyedObjectPoolFactory<RServiPoolKey, PooledRServiWrapper>(factory, config) .createPool(); LOGGER.info("RServi pool instantiated and configured with: " + ToStringBuilder.reflectionToString(config)); } private void registerRServiClientPoolMBean() { try { mbeanExportOperations.registerManagedResource(rServiPool, new ObjectName(Constants.RSERVI_CLIENT_POOL_OBJECT_NAME)); } catch (final Exception e) { LOGGER.error("Failed to register RServi client pool MBean", e); } } @PreDestroy public void terminate() throws Exception { if (rServiPool != null) { rServiPool.close(); LOGGER.info("RServi pool destroyed"); } } public RServi getRServiInstance(final String address, final String clientId, final PoolingStrategy poolingStrategy) throws Exception { if ((rServiPool == null) || (poolingStrategy == PoolingStrategy.NEVER)) { return RServiUtil.getRServi(address, clientId); } else { final PooledRServiWrapper rServi = rServiPool .borrowObject(new RServiPoolKey(address, "pooled-" + clientId)); rServi.resetError(); return rServi; } } }