001/*
002 * JPPF.
003 * Copyright (C) 2005-2016 JPPF Team.
004 * http://www.jppf.org
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.jppf.client;
020
021import java.io.*;
022import java.util.*;
023import java.util.concurrent.CopyOnWriteArrayList;
024import java.util.concurrent.atomic.AtomicBoolean;
025
026import org.jppf.client.event.JobListener;
027import org.jppf.client.persistence.JobPersistence;
028import org.jppf.node.protocol.*;
029import org.jppf.utils.JPPFUuid;
030
031/**
032 * Instances of this class represent a JPPF job and hold all the required elements:
033 * tasks, execution policy, task listener, data provider, priority, blocking indicator.<br>
034 * @author Laurent Cohen
035 */
036public abstract class AbstractJPPFJob implements Serializable, JPPFDistributedJob {
037  /**
038   * Explicit serialVersionUID.
039   */
040  private static final long serialVersionUID = 1L;
041  /**
042   * The list of tasks to execute.
043   */
044  final List<Task<?>> tasks = new ArrayList<>();
045  /**
046   * The container for data shared between tasks.
047   * The data provider should be considered read-only, i.e. no modification will be returned back to the client application.
048   */
049  DataProvider dataProvider = null;
050  /**
051   * Determines whether the execution of this job is blocking on the client side.
052   */
053  boolean blocking = true;
054  /**
055   * The user-defined display name for this job.
056   */
057  String name = null;
058  /**
059   * The universal unique id for this job.
060   */
061  final String uuid;
062  /**
063   * The service level agreement between the job and the server.
064   */
065  JobSLA jobSLA = new JPPFJobSLA();
066  /**
067   * The service level agreement on the client side.
068   */
069  JobClientSLA jobClientSLA = new JPPFJobClientSLA();
070  /**
071   * The user-defined metadata associated with this job.
072   */
073  JobMetadata jobMetadata = new JPPFJobMetadata();
074  /**
075   * The object that holds the results of executed tasks.
076   */
077  final JobResults results = new JobResults();
078  /**
079   * The list of listeners registered with this job.
080   */
081  transient List<JobListener> listeners = new CopyOnWriteArrayList<>();
082  /**
083   * The persistence manager that enables saving and restoring the state of this job.
084   */
085  transient JobPersistence<?> persistenceManager = null;
086  /**
087   * The client that submitted this job.
088   */
089  transient JPPFClient client;
090  /**
091   * Whether this job has been cancelled.
092   */
093  transient AtomicBoolean cancelled = new AtomicBoolean(false);
094  /**
095   * Whether this job is being cancelled.
096   */
097  transient AtomicBoolean cancelling = new AtomicBoolean(false);
098
099  /**
100   * Default constructor, creates a blocking job with no data provider, default SLA values and a priority of 0.
101   * This constructor generates a pseudo-random id as a string of 32 hexadecimal characters.
102   */
103  public AbstractJPPFJob() {
104    this(JPPFUuid.normalUUID());
105  }
106
107  /**
108   * Default constructor, creates a blocking job with no data provider, default SLA values and a priority of 0.
109   * This constructor generates a pseudo-random id as a string of 32 hexadecimal characters.
110   * @param jobUuid the uuid to assign to this job.
111   */
112  public AbstractJPPFJob(final String jobUuid) {
113    this.uuid = (jobUuid == null) ? JPPFUuid.normalUUID() : jobUuid;
114    name = (jobUuid == null) ? this.uuid : jobUuid;
115  }
116
117  @Override
118  public int hashCode() {
119    return 31 + (uuid == null ? 0 : uuid.hashCode());
120  }
121
122  @Override
123  public boolean equals(final Object obj) {
124    if (this == obj) return true;
125    if (!(obj instanceof AbstractJPPFJob)) return false;
126    AbstractJPPFJob other = (AbstractJPPFJob) obj;
127    return (uuid == null) ? other.uuid == null : uuid.equals(other.uuid);
128  }
129
130  /**
131   * Get the object that holds the results of executed tasks.
132   * @return a {@link JobResults} instance.
133   */
134  public JobResults getResults() {
135    return results;
136  }
137
138  /**
139   * Get the service level agreement between the job and the server.
140   * @param jobSLA an instance of <code>JobSLA</code>.
141   * @exclude
142   */
143  public void setSLA(final JobSLA jobSLA) {
144    this.jobSLA = jobSLA;
145  }
146
147  /**
148   * Get the service level agreement between the job and the server.
149   * @param jobClientSLA an instance of <code>JobSLA</code>.
150   * @exclude
151   */
152  public void setClientSLA(final JobClientSLA jobClientSLA) {
153    this.jobClientSLA = jobClientSLA;
154  }
155
156  /**
157   * Set this job's metadata.
158   * @param jobMetadata a {@link JobMetadata} instance.
159   * @exclude
160   */
161  public void setMetadata(final JobMetadata jobMetadata) {
162    this.jobMetadata = jobMetadata;
163  }
164
165  /**
166   * Resolve this instance after deserialization.
167   * @return an instance of {@link Object}.
168   * @exclude
169   */
170  protected Object readResolve() {
171    listeners = new LinkedList<>();
172    return this;
173  }
174
175  @Override
176  public String toString() {
177    StringBuilder sb = new StringBuilder();
178    sb.append(getClass().getSimpleName()).append('[');
179    sb.append("name=").append(name);
180    sb.append(", uuid=").append(uuid);
181    sb.append(", blocking=").append(blocking);
182    sb.append(", nbTasks=").append(tasks.size());
183    sb.append(", nbResults=").append(results.size());
184    sb.append(", jobSLA=").append(jobSLA);
185    sb.append(']');
186    return sb.toString();
187  }
188
189  /**
190   * Get the flag that determines whether this job has been cancelled.
191   * @return an {@code AtomicBoolean} instance.
192   * @exclude
193   */
194  public AtomicBoolean getCancelledFlag() {
195    return cancelled;
196  }
197
198  /**
199   * Get the flag that determines whether this job is being cancelled.
200   * @return an {@code AtomicBoolean} instance.
201   * @exclude
202   */
203  public AtomicBoolean getCancellingFlag() {
204    return cancelling;
205  }
206
207  /**
208   * Save the state of the {@code JPPFJob} instance to a stream (i.e.,serialize it).
209   * @param out the output stream to which to write the job. 
210   * @throws IOException if any I/O error occurs.
211   * @since 5.0
212   */
213  private void writeObject(final ObjectOutputStream out) throws IOException {
214    out.defaultWriteObject();
215  }
216
217  /**
218   * Reconstitute the {@code TreeMap} instance from a stream (i.e., deserialize it).
219   * @param in the input stream from which to read the job. 
220   * @throws IOException if any I/O error occurs.
221   * @throws ClassNotFoundException if the class of an object in the object graph can not be found.
222   * @since 5.0
223   */
224  private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
225    in.defaultReadObject();
226    cancelled = new AtomicBoolean(false);
227    cancelling = new AtomicBoolean(false);
228  }
229}