package org.infinispan.tasks.impl;
import static org.infinispan.tasks.logging.Messages.MESSAGES;
import java.lang.invoke.MethodHandles;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentMap;
import javax.security.auth.Subject;
import org.infinispan.commons.util.CollectionFactory;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.factories.scopes.Scope;
import org.infinispan.factories.scopes.Scopes;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.remoting.transport.Address;
import org.infinispan.security.Security;
import org.infinispan.tasks.Task;
import org.infinispan.tasks.TaskContext;
import org.infinispan.tasks.TaskExecution;
import org.infinispan.tasks.TaskManager;
import org.infinispan.tasks.logging.Log;
import org.infinispan.tasks.spi.TaskEngine;
import org.infinispan.util.TimeService;
import org.infinispan.util.logging.LogFactory;
import org.infinispan.util.logging.events.EventLogCategory;
import org.infinispan.util.logging.events.EventLogManager;
import org.infinispan.util.logging.events.EventLogger;
/**
* TaskManagerImpl.
*
* @author Tristan Tarrant
* @since 8.1
*/
@Scope(Scopes.GLOBAL)
public class TaskManagerImpl implements TaskManager {
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass(), Log.class);
private EmbeddedCacheManager cacheManager;
private List<TaskEngine> engines;
private ConcurrentMap<UUID, TaskExecution> runningTasks;
private TimeService timeService;
private boolean useSecurity;
public TaskManagerImpl() {
engines = new ArrayList<>();
runningTasks = CollectionFactory.makeConcurrentMap();
}
@Inject
public void initialize(final EmbeddedCacheManager cacheManager, final TimeService timeService) {
this.cacheManager = cacheManager;
this.timeService = timeService;
this.useSecurity = cacheManager.getCacheManagerConfiguration().security().authorization().enabled();
}
public synchronized void registerTaskEngine(TaskEngine engine) {
if (engines.contains(engine)) {
throw log.duplicateTaskEngineRegistration(engine.getName());
} else {
engines.add(engine);
}
}
@Override
public <T> CompletableFuture<T> runTask(String name, TaskContext context) {
for(TaskEngine engine : engines) {
if (engine.handles(name)) {
context.cacheManager(cacheManager);
Address address = cacheManager.getAddress();
Optional<String> who;
if (useSecurity) {
Subject subject = Security.getSubject();
Principal userPrincipal = Security.getSubjectUserPrincipal(subject);
who = Optional.of(userPrincipal.getName());
} else {
who = Optional.empty();
}
TaskExecutionImpl exec = new TaskExecutionImpl(name, address == null ? "local" : address.toString(), who, context);
exec.setStart(timeService.instant());
runningTasks.put(exec.getUUID(), exec);
CompletableFuture<T> task = engine.runTask(name, context);
return task.whenComplete((r, e) -> {
if (context.isLogEvent()) {
EventLogger eventLog = EventLogManager.getEventLogger(cacheManager).scope(cacheManager.getAddress());
who.ifPresent(s -> eventLog.who(s));
context.getCache().ifPresent(cache -> eventLog.context(cache));
if (e != null) {
eventLog.detail(e)
.error(EventLogCategory.TASKS, MESSAGES.taskFailure(name));
} else {
eventLog.detail(String.valueOf(r))
.info(EventLogCategory.TASKS, MESSAGES.taskSuccess(name));
}
}
runningTasks.remove(exec.getUUID());
});
}
}
throw log.unknownTask(name);
}
@Override
public List<TaskExecution> getCurrentTasks() {
return new ArrayList<>(runningTasks.values());
}
@Override
public List<TaskEngine> getEngines() {
return Collections.unmodifiableList(engines);
}
@Override
public List<Task> getTasks() {
List<Task> tasks = new ArrayList<>();
engines.forEach(engine -> tasks.addAll(engine.getTasks()));
return tasks;
}
}