/*
* JBoss, Home of Professional Open Source.
* Copyright 2015, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.extension.batch.jberet.deployment;
import java.util.Properties;
import javax.enterprise.inject.spi.BeanManager;
import javax.transaction.TransactionManager;
import org.jberet.repository.JobRepository;
import org.jberet.spi.ArtifactFactory;
import org.jberet.spi.BatchEnvironment;
import org.jberet.spi.JobExecutor;
import org.jberet.spi.JobTask;
import org.jberet.spi.JobXmlResolver;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.msc.value.InjectedValue;
import org.wildfly.extension.batch.jberet.BatchConfiguration;
import org.wildfly.extension.batch.jberet._private.BatchLogger;
import org.wildfly.extension.requestcontroller.ControlPoint;
import org.wildfly.extension.requestcontroller.RequestController;
import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.auth.server.SecurityIdentity;
import org.wildfly.security.manager.WildFlySecurityManager;
/**
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
*/
public class BatchEnvironmentService implements Service<SecurityAwareBatchEnvironment> {
private static final Properties PROPS = new Properties();
private final InjectedValue<BeanManager> beanManagerInjector = new InjectedValue<>();
private final InjectedValue<JobExecutor> jobExecutorInjector = new InjectedValue<>();
private final InjectedValue<TransactionManager> transactionManagerInjector = new InjectedValue<>();
private final InjectedValue<RequestController> requestControllerInjector = new InjectedValue<>();
private final InjectedValue<JobRepository> jobRepositoryInjector = new InjectedValue<>();
private final InjectedValue<BatchConfiguration> batchConfigurationInjector = new InjectedValue<>();
private final ClassLoader classLoader;
private final JobXmlResolver jobXmlResolver;
private final String deploymentName;
private SecurityAwareBatchEnvironment batchEnvironment = null;
private volatile ControlPoint controlPoint;
public BatchEnvironmentService(final ClassLoader classLoader, final JobXmlResolver jobXmlResolver, final String deploymentName) {
this.classLoader = classLoader;
this.jobXmlResolver = jobXmlResolver;
this.deploymentName = deploymentName;
}
@Override
public synchronized void start(final StartContext context) throws StartException {
BatchLogger.LOGGER.debugf("Creating batch environment; %s", classLoader);
final BatchConfiguration batchConfiguration = batchConfigurationInjector.getValue();
// Find the job executor to use
JobExecutor jobExecutor = jobExecutorInjector.getOptionalValue();
if (jobExecutor == null) {
jobExecutor = batchConfiguration.getDefaultJobExecutor();
}
// Find the job repository to use
JobRepository jobRepository = jobRepositoryInjector.getOptionalValue();
if (jobRepository == null) {
jobRepository = batchConfiguration.getDefaultJobRepository();
}
this.batchEnvironment = new WildFlyBatchEnvironment(beanManagerInjector.getOptionalValue(),
jobExecutor, transactionManagerInjector.getValue(),
jobRepository, jobXmlResolver);
final RequestController requestController = requestControllerInjector.getOptionalValue();
if (requestController != null) {
// Create the entry point
controlPoint = requestController.getControlPoint(deploymentName, "batch-executor-service");
} else {
controlPoint = null;
}
}
@Override
public synchronized void stop(final StopContext context) {
BatchLogger.LOGGER.debugf("Removing batch environment; %s", classLoader);
batchEnvironment = null;
if (controlPoint != null) {
requestControllerInjector.getValue().removeControlPoint(controlPoint);
}
}
@Override
public synchronized SecurityAwareBatchEnvironment getValue() throws IllegalStateException, IllegalArgumentException {
return batchEnvironment;
}
public InjectedValue<BeanManager> getBeanManagerInjector() {
return beanManagerInjector;
}
public InjectedValue<JobExecutor> getJobExecutorInjector() {
return jobExecutorInjector;
}
public InjectedValue<TransactionManager> getTransactionManagerInjector() {
return transactionManagerInjector;
}
public InjectedValue<RequestController> getRequestControllerInjector() {
return requestControllerInjector;
}
public InjectedValue<JobRepository> getJobRepositoryInjector() {
return jobRepositoryInjector;
}
public InjectedValue<BatchConfiguration> getBatchConfigurationInjector() {
return batchConfigurationInjector;
}
private class WildFlyBatchEnvironment implements BatchEnvironment, SecurityAwareBatchEnvironment {
private final ArtifactFactory artifactFactory;
private final JobExecutor jobExecutor;
private final TransactionManager transactionManager;
private final JobRepository jobRepository;
private final JobXmlResolver jobXmlResolver;
WildFlyBatchEnvironment(final BeanManager beanManager,
final JobExecutor jobExecutor,
final TransactionManager transactionManager,
final JobRepository jobRepository,
final JobXmlResolver jobXmlResolver) {
this.jobXmlResolver = jobXmlResolver;
artifactFactory = new WildFlyArtifactFactory(beanManager);
this.jobExecutor = jobExecutor;
this.transactionManager = transactionManager;
this.jobRepository = jobRepository;
}
@Override
public ClassLoader getClassLoader() {
return classLoader;
}
@Override
public ArtifactFactory getArtifactFactory() {
return artifactFactory;
}
@Override
public void submitTask(final JobTask jobTask) {
final SecurityIdentity identity = getIdentity();
final ContextHandle contextHandle = createContextHandle();
final JobTask task = new JobTask() {
@Override
public int getRequiredRemainingPermits() {
return jobTask.getRequiredRemainingPermits();
}
@Override
public void run() {
final ContextHandle.Handle handle = contextHandle.setup();
try {
if (identity == null) {
jobTask.run();
} else {
identity.runAs(jobTask);
}
} finally {
handle.tearDown();
}
}
};
if (controlPoint == null) {
jobExecutor.execute(task);
} else {
// Queue the task to run in the control point, if resume is executed the queued tasks will run
controlPoint.queueTask(task, jobExecutor, -1, null, false);
}
}
@Override
public TransactionManager getTransactionManager() {
return transactionManager;
}
@Override
public JobRepository getJobRepository() {
return jobRepository;
}
@Override
public JobXmlResolver getJobXmlResolver() {
return jobXmlResolver;
}
@Override
public Properties getBatchConfigurationProperties() {
return PROPS;
}
@Override
public SecurityDomain getSecurityDomain() {
return batchConfigurationInjector.getValue().getSecurityDomain();
}
private ContextHandle createContextHandle() {
final ClassLoader tccl = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged();
// If the TCCL is null, use the deployments ModuleClassLoader
final ClassLoaderContextHandle classLoaderContextHandle = (tccl == null ? new ClassLoaderContextHandle(classLoader) : new ClassLoaderContextHandle(tccl));
// Class loader handle must be first so the TCCL is set before the other handles execute
return new ContextHandle.ChainedContextHandle(classLoaderContextHandle, new NamespaceContextHandle(), new SecurityContextHandle());
}
}
}