content: 
  /*
   * Copyright Contributors to the OpenCue Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
   * in compliance with the License. You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software distributed under the License
   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
   * or implied. See the License for the specific language governing permissions and limitations under
   * the License.
   */
  
  package com.imageworks.spcue.service;
  
  import java.io.File;
  import java.util.HashSet;
  import java.util.Set;
  
  import org.apache.logging.log4j.Logger;
  import org.apache.logging.log4j.LogManager;
  import org.springframework.beans.BeansException;
  import org.springframework.context.ApplicationContext;
  import org.springframework.context.ApplicationContextAware;
  import org.springframework.dao.DataIntegrityViolationException;
  import org.springframework.dao.EmptyResultDataAccessException;
  import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
  
  import com.imageworks.spcue.BuildableJob;
  import com.imageworks.spcue.EntityCreationError;
  import com.imageworks.spcue.JobDetail;
  import com.imageworks.spcue.LocalHostAssignment;
  import com.imageworks.spcue.ShowEntity;
  import com.imageworks.spcue.dispatcher.commands.DispatchLaunchJob;
  import com.imageworks.spcue.grpc.renderpartition.RenderPartitionType;
  
  /**
   * Job launching functions.
   */
  public class JobLauncher implements ApplicationContextAware {
      private static final Logger logger = LogManager.getLogger(JobLauncher.class);
      private ApplicationContext context;
  
      private JobManager jobManager;
      private DepartmentManager departmentManager;
      private AdminManager adminManager;
      private ThreadPoolTaskExecutor launchQueue;
      private EmailSupport emailSupport;
      private JmsMover jmsMover;
      private LocalBookingSupport localBookingSupport;
  
      /**
       * When true, disables log path creation and proc points sync.
       */
      public volatile boolean testMode = false;
  
      @Override
      public void setApplicationContext(ApplicationContext context) throws BeansException {
          this.context = context;
      }
  
      public JobSpec parse(String xml) {
          JobSpec spec = (JobSpec) this.context.getBean("jobSpec");
          spec.parse(xml);
          return spec;
      }
  
      public JobSpec parse(File file) {
          JobSpec spec = (JobSpec) this.context.getBean("jobSpec");
          spec.parse(file);
          return spec;
      }
  
      public void launch(String xml) {
          JobSpec spec = (JobSpec) this.context.getBean("jobSpec");
          spec.parse(xml);
          launch(spec);
      }
  
      public void launch(File file) {
          JobSpec spec = (JobSpec) this.context.getBean("jobSpec");
          spec.parse(file);
          launch(spec);
      }
  
      public void launch(final JobSpec spec) {
  
          verifyJobSpec(spec);
  
          try {
              jobManager.launchJobSpec(spec);
  
              for (BuildableJob job : spec.getJobs()) {
                  /*
                   * If isLocal is set, need to create local host assignment.
                   */
                  JobDetail d = job.detail;
                  if (d.isLocal) {
                      logger.info(d.localHostName + " will do local dispatch. " + d.getJobId() + " "
                              + d.localHostName);
                      LocalHostAssignment lha = new LocalHostAssignment();
                      lha.setJobId(d.getJobId());
                      lha.setThreads(d.localThreadNumber);
                      lha.setMaxCoreUnits(d.localMaxCores * 100);
                      lha.setMaxMemory(d.localMaxMemory);
                      lha.setMaxGpuUnits(d.localMaxGpus);
                      lha.setMaxGpuMemory(d.localMaxGpuMemory);
                      lha.setType(RenderPartitionType.JOB_PARTITION);
  
                      try {
                          localBookingSupport.bookLocal(d, d.localHostName, d.user, lha);
                      } catch (DataIntegrityViolationException e) {
                          logger.info(d.name + " failed to create host local assignment.");
                      }
                  }
              }
  
              /*
               * This has to happen outside of the job launching transaction or else it can lock up
               * booking because it updates the job_resource table. It can take quite some time to
               * launch a job with dependencies, so the transaction should not touch any rows that are
               * currently in the "live" data set.
               */
              if (!testMode) {
                  Set<String> depts = new HashSet<String>();
                  for (BuildableJob job : spec.getJobs()) {
                      JobDetail d = jobManager.getJobDetail(job.detail.id);
                      jmsMover.send(d);
                      if (departmentManager.isManaged(d)) {
                          if (!depts.contains(d.deptId)) {
                              departmentManager.syncJobsWithTask(d);
                              depts.add(d.deptId);
                          }
                      }
                  }
              }
          } catch (Exception e) {
              // Catch anything and email the user a report as to
              // why the job launch failed.
              emailSupport.reportLaunchError(spec, e);
          }
      }
  
      public void verifyJobSpec(JobSpec spec) {
  
          for (BuildableJob job : spec.getJobs()) {
              if (jobManager.isJobPending(job.detail.name)) {
                  throw new EntityCreationError("The job " + job.detail.name + " is already pending");
              }
          }
  
          try {
              ShowEntity s = adminManager.findShowEntity(spec.getShow());
              if (!s.active) {
                  throw new EntityCreationError("The " + spec.getShow()
                          + " show has been deactivated.  Please contact "
                          + "administrator of your OpenCue deployment to reactivate " + "this show.");
              }
          } catch (EmptyResultDataAccessException e) {
              throw new EntityCreationError("The " + spec.getShow()
                      + " does not exist. Please contact "
                      + "administrator of your OpenCue deployment to have this show " + "created.");
          }
      }
  
      public void queueAndLaunch(final JobSpec spec) {
          verifyJobSpec(spec);
          launchQueue.execute(new DispatchLaunchJob(spec, this));
      }
  
      public EmailSupport getEmailSupport() {
          return emailSupport;
      }
  
      public void setEmailSupport(EmailSupport emailSupport) {
          this.emailSupport = emailSupport;
      }
  
      public JobManager getJobManager() {
          return jobManager;
      }
  
      public void setJobManager(JobManager jobManager) {
          this.jobManager = jobManager;
      }
  
      public DepartmentManager getDepartmentManager() {
          return departmentManager;
      }
  
      public void setDepartmentManager(DepartmentManager departmentManager) {
          this.departmentManager = departmentManager;
      }
  
      public AdminManager getAdminManager() {
          return adminManager;
      }
  
      public void setAdminManager(AdminManager adminManager) {
          this.adminManager = adminManager;
      }
  
      public ThreadPoolTaskExecutor getLaunchQueue() {
          return launchQueue;
      }
  
      public void setLaunchQueue(ThreadPoolTaskExecutor launchQueue) {
          this.launchQueue = launchQueue;
      }
  
      public JmsMover getJmsMover() {
          return jmsMover;
      }
  
      public void setJmsMover(JmsMover jmsMover) {
          this.jmsMover = jmsMover;
      }
  
      public LocalBookingSupport getLocalBookingSupport() {
          return localBookingSupport;
      }
  
      public void setLocalBookingSupport(LocalBookingSupport localBookingSupport) {
          this.localBookingSupport = localBookingSupport;
      }
  }
  