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

org.jppf.server.protocol.AbstractServerJob Maven / Gradle / Ivy

There is a newer version: 6.3-alpha
Show newest version
/*
 * JPPF.
 * Copyright (C) 2005-2015 JPPF Team.
 * http://www.jppf.org
 *
 * 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 org.jppf.server.protocol;

import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;

import org.jppf.execute.ExecutorChannel;
import org.jppf.node.protocol.*;
import org.jppf.server.submission.SubmissionStatus;
import org.jppf.utils.LoggingUtils;
import org.slf4j.*;

/**
 * Abstract class that support job state management.
 * @author Martin JANDA
 */
public abstract class AbstractServerJob {
  /**
   * Logger for this class.
   */
  private static final Logger log = LoggerFactory.getLogger(ServerJob.class);
  /**
   * Determines whether DEBUG logging level is enabled.
   */
  private static boolean debugEnabled = LoggingUtils.isDebugEnabled(log);
  /**
   * Count of instances of this class.
   */
  private static final AtomicLong INSTANCE_COUNT = new AtomicLong(0L);
  /**
   * A unique id for this client bundle.
   */
  protected final long id = INSTANCE_COUNT.incrementAndGet();
  /**
   * The job status.
   */
  protected volatile ServerJobStatus status = ServerJobStatus.NEW;
  /**
   * List of all runnables called on job completion.
   */
  protected final List onDoneList = new ArrayList<>();
  /**
   * Time at which the job is received on the server side. In milliseconds since January 1, 1970 UTC.
   */
  protected long jobReceivedTime = 0L;
  /**
   * The time at which this wrapper was added to the queue.
   */
  protected transient long queueEntryTime = 0L;
  /**
   * The underlying task bundle.
   */
  protected final TaskBundle job;
  /**
   * The universal unique id for this job.
   */
  protected String uuid = null;
  /**
   * The user-defined display name for this job.
   */
  protected String name = null;
  /**
   * The service level agreement between the job and the server.
   */
  protected JobSLA sla = null;
  /**
   * The job metadata.
   */
  protected JobMetadata metadata = null;
  /**
   * Job expired indicator, determines whether the job is should be cancelled.
   */
  protected boolean jobExpired = false;
  /**
   * Job pending indicator, determines whether the job is waiting for its scheduled time to start.
   */
  protected boolean pending = false;
  /**
   * Used for synchronized access to job.
   */
  protected final Lock lock;
  /**
   * The status of this submission.
   */
  protected SubmissionStatus submissionStatus;
  /**
   * Handler for job state notifications.
   */
  protected ServerJobChangeListener notificationEmitter;
  /**
   * List of bundles added after submission status set to COMPLETE.
   */
  protected List completionBundles = null;

  /**
   * Initialized abstract client job with task bundle and list of tasks to execute.
   * @param lock used to synchronized access to job.
   * @param job  underlying task bundle.
   */
  protected AbstractServerJob(final Lock lock, final TaskBundle job) {
    if (lock == null) throw new IllegalArgumentException("lock is null");
    if (job == null) throw new IllegalArgumentException("job is null");
    if (debugEnabled) log.debug("creating ClientJob #" + id);
    this.lock = lock;
    this.job = job;
    this.uuid = this.job.getUuid();
    this.name = this.job.getName();
    this.sla = this.job.getSLA();
    this.metadata = this.job.getMetadata();
    this.submissionStatus = SubmissionStatus.SUBMITTED;
  }

  /**
   * Get the underlying task bundle.
   * @return a ClientTaskBundle instance.
   */
  public TaskBundle getJob() {
    return job;
  }

  /**
   * Get the universal unique id for this job.
   * @return the uuid as a string.
   * @exclude
   */
  public String getUuid() {
    return uuid;
  }

  /**
   * Set the universal unique id for this job.
   * @param uuid the universal unique id.
   */
  public void setUuid(final String uuid) {
    this.uuid = uuid;
  }

  /**
   * Get the user-defined display name for this job. This is the name displayed in the administration console.
   * @return the name as a string.
   */
  public String getName() {
    return name;
  }

  /**
   * Set the user-defined display name for this job.
   * @param name the display name as a string.
   */
  public void setName(final String name) {
    this.name = name;
  }

  /**
   * Get the service level agreement between the job and the server.
   * @return an instance of {@link org.jppf.node.protocol.JobSLA}.
   */
  public JobSLA getSLA() {
    return sla;
  }

  /**
   * Get the job metadata.
   * @return an instance of {@link JobMetadata}.
   */
  public JobMetadata getMetadata() {
    return metadata;
  }

  /**
   * Set the job metadata.
   * @param metadata an instance of {@link JobMetadata}.
   */
  public void setMetadata(final JobMetadata metadata) {
    this.metadata = metadata;
  }

  /**
   * Get the service level agreement between the job and the server.
   * @param sla an instance of JobSLA.
   */
  public void setSLA(final JobSLA sla) {
    this.sla = sla;
  }

  /**
   * Get the job expired indicator.
   * @return true if job has expired, false otherwise.
   */
  public boolean isJobExpired() {
    return jobExpired;
  }

  /**
   * Sets and notifies that job has expired.
   */
  public void jobExpired() {
    this.jobExpired = true;
  }

  /**
   * Get the job pending indicator.
   * @return true if job is pending, false otherwise.
   */
  public boolean isPending() {
    return pending;
  }

  /**
   * Set the job pending indicator.
   * @param pending true to indicate that job is pending, false otherwise
   */
  public void setPending(final boolean pending) {
    boolean oldValue = isPending();
    this.pending = pending;
    boolean newValue = isPending();
    if (oldValue != newValue) fireJobUpdated();
  }

  /**
   * Get the job suspended indicator.
   * @return true if job is suspended, false otherwise.
   */
  public boolean isSuspended() {
    return getJob().getSLA().isSuspended();
  }
  
  /**
   * Set the job suspended indicator.
   * @param suspended true to indicate that job is suspended, false otherwise.
   * @param requeue true to indicate that job should be requeued, false otherwise.
   */
  public void setSuspended(final boolean suspended, final boolean requeue) {
    JobSLA sla = getJob().getSLA();
    if (sla.isSuspended() == suspended) return;
    sla.setSuspended(suspended);
    fireJobUpdated();
  }

  /**
   * Set the maximum number of nodes this job can run on.
   * @param maxNodes the number of nodes as an int value. A value <= 0 means no limit on the number of nodes.
   */
  public void setMaxNodes(final int maxNodes) {
    if (maxNodes <= 0) return;
    getJob().getSLA().setMaxNodes(maxNodes);
    fireJobUpdated();
  }

  /**
   * Updates status to new value if old value is equal to expect.
   * @param expect the expected value.
   * @param newStatus the new value.
   * @return true if new status was set.
   */
  protected final boolean updateStatus(final ServerJobStatus expect, final ServerJobStatus newStatus) {
    if (status == expect) {
      status = newStatus;
      return true;
    }
    else return false;
  }

  /**
   * Get the status of this job.
   * @return a {@link ServerJobStatus} enum value.
   */
  public ServerJobStatus getStatus() {
    return status;
  }

  /**
   * @return true when job is cancelled or finished normally.
   */
  public boolean isDone() {
    return status.compareTo(ServerJobStatus.DONE) >= 0;
  }

  /**
   * @return true when job was cancelled.
   */
  public boolean isCancelled() {
    return status.compareTo(ServerJobStatus.CANCELLED) >= 0;
  }

  /**
   * Cancels this job.
   * @param mayInterruptIfRunning true if the thread executing this task should be interrupted.
   * @return whether cancellation was successful.
   */
  public boolean setCancelled(final boolean mayInterruptIfRunning) {
    if (!isSuspended() && (status.ordinal() > ServerJobStatus.EXECUTING.ordinal())) return false;
    status = ServerJobStatus.CANCELLED;
    return true;
  }

  /**
   * Called when task was cancelled or finished.
   */
  protected void done() {
    Runnable[] runnables;
    synchronized (onDoneList) {
      runnables = onDoneList.toArray(new Runnable[onDoneList.size()]);
    }
    for (Runnable runnable : runnables) runnable.run();
  }

  /**
   * Registers instance to be called on job finish.
   * @param runnable {@link Runnable} to be called on job finish.
   */
  public void addOnDone(final Runnable runnable) {
    if (runnable == null) throw new IllegalArgumentException("runnable is null");
    synchronized (onDoneList) {
      onDoneList.add(runnable);
    }
  }

  /**
   * Deregisters instance to be called on job finish.
   * @param runnable {@link Runnable} to be called on job finish.
   */
  public void removeOnDone(final Runnable runnable) {
    if (runnable == null) throw new IllegalArgumentException("runnable is null");
    synchronized (onDoneList) {
      onDoneList.remove(runnable);
    }
  }

  /**
   * Get the job received time.
   * @return the time in milliseconds as a long value.
   */
  public long getJobReceivedTime() {
    return jobReceivedTime;
  }

  /**
   * Set the job received time.
   * @param jobReceivedTime the time in milliseconds as a long value.
   */
  public void setJobReceivedTime(final long jobReceivedTime) {
    this.jobReceivedTime = jobReceivedTime;
  }

  /**
   * Get the time at which this wrapper was added to the queue.
   * @return the time in milliseconds as a long value.
   */
  public long getQueueEntryTime() {
    return queueEntryTime;
  }

  /**
   * Set the time at which this wrapper was added to the queue.
   * @param queueEntryTime the time in milliseconds as a long value.
   */
  public void setQueueEntryTime(final long queueEntryTime) {
    this.queueEntryTime = queueEntryTime;
  }

    /**
    * Get the current number of tasks in the job.
    * @return the number of tasks as an int.
    */
  public abstract int getTaskCount();

  /**
   * Get the initial task count.
   * @return the count as an int.
   */
  public int getInitialTaskCount() {
    return job.getInitialTaskCount();
  }

  /**
   * Get the status of this submission.
   * @return a {@link SubmissionStatus} enumerated value.
   */
  public SubmissionStatus getSubmissionStatus() {
    lock.lock();
    try {
      return submissionStatus;
    } finally {
      lock.unlock();
    }
  }

  /**
   * Set the status of this submission.
   * @param submissionStatus a {@link SubmissionStatus} enumerated value.
   */
  public void setSubmissionStatus(final SubmissionStatus submissionStatus) {
    lock.lock();
    try {
      if (this.submissionStatus == submissionStatus) return;
      SubmissionStatus oldValue = this.submissionStatus;
      this.submissionStatus = submissionStatus;
      fireStatusChanged(oldValue, this.submissionStatus);
      if (submissionStatus == SubmissionStatus.ENDED) done();
    } finally {
      lock.unlock();
    }
  }

  /**
   * Notify that job submission status has changed.
   * @param oldValue value before change.
   * @param newValue value after change.
   */
  protected void fireStatusChanged(final SubmissionStatus oldValue, final SubmissionStatus newValue) {
    if (notificationEmitter != null) notificationEmitter.jobStatusChanged(this, oldValue, newValue);
  }

  /**
   * Get the broadcast UUID.
   * @return an String instance.
   */
  public String getBroadcastUUID() {
    return null;
  }

  /**
   * Get list of bundles added after job completion.
   * @return list of bundles added after job completion.
   */
  public List getCompletionBundles() {
    lock.lock();
    try {
      if(completionBundles == null) return Collections.emptyList();
      else return new ArrayList<>(completionBundles);
    } finally {
      lock.unlock();
    }
  }

  /**
   * The current number of tasks in a job was updated.
   */
  public void fireJobUpdated() {
    if (notificationEmitter != null) notificationEmitter.jobUpdated(this);
  }

  /**
   * A sub-job was dispatched to a node.
   * @param channel the node to which the job is dispatched.
   * @param bundleNode the bundle for job event.
   */
  protected void fireJobDispatched(final ExecutorChannel channel, final ServerTaskBundleNode bundleNode) {
    if (notificationEmitter != null) notificationEmitter.jobDispatched(this, channel, bundleNode);
  }

  /**
   * A sub-job returned from a node.
   * @param channel the node from which the job is returned.
   * @param bundleNode the bundle for job event.
   */
  protected void fireJobReturned(final ExecutorChannel channel, final ServerTaskBundleNode bundleNode) {
    if (notificationEmitter != null) notificationEmitter.jobReturned(this, channel, bundleNode);
  }

  /**
   * Get the lock used for synchronized access to job.
   * @return a {@link Lock} object.
   */
  public Lock getLock() {
    return lock;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy