/**
* Copyright © 2013 enioka. All rights reserved
* Authors: Marc-Antoine GOUILLART (marc-antoine.gouillart@enioka.com)
* Pierre COPPEE (pierre.coppee@enioka.com)
*
* 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.enioka.jqm.model;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import com.enioka.jqm.jdbc.DatabaseException;
import com.enioka.jqm.jdbc.DbConn;
import com.enioka.jqm.jdbc.QueryResult;
/**
* <strong>Not part of any API - this an internal JQM class and may change without notice.</strong> <br>
* Persistence class for storing the execution requests. Said otherwise, <strong>this table holds the contents of the execution
* queues</strong>.
*/
public class JobInstance implements Serializable
{
private static final long serialVersionUID = -7710486847228806301L;
private Integer id;
private int jd_id;
private int queue_id;
private int node_id;
private State state;
private double internalPosition;
private boolean highlander;
private Integer parentId;
private String email;
private Integer progress;
private Calendar creationDate;
private Calendar attributionDate;
private Calendar executionDate;
private String userName;
private String sessionID;
private String instanceApplication;
private String instanceModule;
private String instanceKeyword1;
private String instanceKeyword2;
private String instanceKeyword3;
private JobDef jd;
private Queue q;
private Node n;
/**
* Helper method to add a parameter without having to create it explicitely. The created parameter should be persisted afterwards.
*
* @param key
* name of the parameter to add
* @param value
* value of the parameter to create
* @return the newly created parameter
*/
public RuntimeParameter addParameter(String key, String value)
{
RuntimeParameter jp = new RuntimeParameter();
jp.setJi(this.getId());
jp.setKey(key);
jp.setValue(value);
return jp;
}
/**
* A technical ID without any meaning. Generated by the database.
*/
public int getId()
{
return id;
}
/**
* An optional classification tag which can be specified inside the execution request (default is NULL).
*/
public String getUserName()
{
return userName;
}
/**
* An optional classification tag which can be specified inside the execution request (default is NULL).
*/
public String getSessionID()
{
return sessionID;
}
/**
* The {@link JobDef} from which this {@link JobInstance} was instantiated.
*/
public int getJd()
{
return jd_id;
}
public JobDef getJD()
{
return jd;
}
public Queue getQ()
{
return q;
}
/**
* See {@link #getJd()}
*/
public void setJd(final int jd)
{
this.jd_id = jd;
}
/**
* The current status of the request. See {@link State}.
*/
public State getState()
{
return state;
}
/**
* See {@link #getState()}
*/
public void setState(State state)
{
this.state = state;
}
/**
* See {@link #getUserName()}
*/
public void setUserName(final String user)
{
this.userName = user;
}
/**
* See {@link #getSessionID()}
*/
public void setSessionID(final String sessionID)
{
this.sessionID = sessionID;
}
/**
* The {@link Queue} on which is the {@link JobInstance} should wait. Cannot be changed once the status is ATTRIBUTED (i.e. wait is
* over).
*/
public int getQueue()
{
return queue_id;
}
/**
* See {@link #getQueue()}
*/
public void setQueue(final int queue)
{
this.queue_id = queue;
}
/**
* The node that is running the {@link JobInstance}. Null until wait is over and status is ATTRIBUTED.
*/
public Node getNode()
{
return n;
}
/**
* See {@link #getNode()}
*/
public void setNode(final int node)
{
this.node_id = node;
}
/**
* Null by default. If specified, an e-mail will be sent to this address at run end.
*/
public String getEmail()
{
return email;
}
/**
* See {@link #getEmail()}
*/
public void setEmail(String email)
{
this.email = email;
}
/**
* User code may signal its progress through this integer. Purely optional.
*/
public Integer getProgress()
{
return progress;
}
/**
* See {@link #getProgress()}
*/
public void setProgress(Integer progress)
{
this.progress = progress;
}
/**
* Technical queue ordering field.
*/
public double getInternalPosition()
{
return internalPosition;
}
/**
* See {@link #getInternalPosition()}
*/
public void setInternalPosition(double internalPosition)
{
this.internalPosition = internalPosition;
}
/**
* Only set when a job request is created by a running job, in which case it contains the job {@link JobInstance} ID.
*/
public Integer getParentId()
{
return parentId;
}
/**
* See {@link #getParentId()}
*/
public void setParentId(Integer parentId)
{
this.parentId = parentId;
}
/**
* Time at which this {@link JobInstance} was committed inside the database.
*/
public Calendar getCreationDate()
{
return creationDate;
}
/**
* See {@link #getCreationDate()}
*/
public void setCreationDate(Calendar creationDate)
{
this.creationDate = creationDate;
}
/**
* An optional classification tag which can be specified inside the execution request (default is NULL).
*/
public String getApplication()
{
return instanceApplication;
}
/**
* See {@link #getApplication()}
*/
public void setApplication(String application)
{
this.instanceApplication = application;
}
/**
* An optional classification tag which can be specified inside the execution request (default is NULL).
*/
public String getModule()
{
return instanceModule;
}
/**
* See {@link #getModule()}
*/
public void setModule(String module)
{
this.instanceModule = module;
}
/**
* An optional classification tag which can be specified inside the execution request (default is NULL).
*/
public String getKeyword1()
{
return instanceKeyword1;
}
/**
* See {@link #getKeyword1()}
*/
public void setKeyword1(String keyword1)
{
this.instanceKeyword1 = keyword1;
}
/**
* An optional classification tag which can be specified inside the execution request (default is NULL).
*/
public String getKeyword2()
{
return instanceKeyword2;
}
/**
* See {@link #getKeyword2()}
*/
public void setKeyword2(String keyword2)
{
this.instanceKeyword2 = keyword2;
}
/**
* An optional classification tag which can be specified inside the execution request (default is NULL).
*/
public String getKeyword3()
{
return instanceKeyword3;
}
/**
* See {@link #getKeyword3()}
*/
public void setKeyword3(String keyword3)
{
this.instanceKeyword3 = keyword3;
}
void setId(Integer id)
{
this.id = id;
}
/**
* Time at which the execution request entered the RUNNING status - a few milliseconds before actual execution.
*/
public Calendar getExecutionDate()
{
return executionDate;
}
/**
* See {@link #getExecutionDate()}
*/
public void setExecutionDate(Calendar executionDate)
{
this.executionDate = executionDate;
}
/**
* Time at which the job execution request (the {@link JobInstance}) was taken by an engine.
*/
public Calendar getAttributionDate()
{
return attributionDate;
}
/**
* See {@link #getAttributionDate()}
*/
public void setAttributionDate(Calendar attributionDate)
{
this.attributionDate = attributionDate;
}
public static List<JobInstance> select(DbConn cnx, String query_key, Object... args)
{
List<JobInstance> res = new ArrayList<JobInstance>();
ResultSet rs = null;
try
{
rs = cnx.runSelect(query_key, args);
while (rs.next())
{
JobInstance tmp = new JobInstance();
tmp.id = rs.getInt(1);
tmp.attributionDate = cnx.getCal(rs, 2);
tmp.creationDate = cnx.getCal(rs, 3);
tmp.email = rs.getString(4);
tmp.executionDate = cnx.getCal(rs, 5);
tmp.instanceApplication = rs.getString(6);
tmp.instanceKeyword1 = rs.getString(7);
tmp.instanceKeyword2 = rs.getString(8);
tmp.instanceKeyword3 = rs.getString(9);
tmp.instanceModule = rs.getString(10);
tmp.internalPosition = rs.getDouble(11);
tmp.parentId = rs.getInt(12);
tmp.progress = rs.getInt(13);
tmp.sessionID = rs.getString(14);
tmp.state = State.valueOf(rs.getString(15));
tmp.userName = rs.getString(16);
tmp.jd_id = rs.getInt(17);
tmp.node_id = rs.getInt(18);
tmp.queue_id = rs.getInt(19);
tmp.highlander = rs.getBoolean(20);
tmp.q = Queue.map(rs, 20);
tmp.jd = JobDef.map(rs, 24);
tmp.n = Node.map(cnx, rs, 42);
res.add(tmp);
}
}
catch (SQLException e)
{
throw new DatabaseException(e);
}
finally
{
cnx.closeQuietly(rs);
}
return res;
}
public static JobInstance select_id(DbConn cnx, int id)
{
List<JobInstance> res = select(cnx, "ji_select_by_id", id);
if (res.isEmpty())
{
throw new DatabaseException("no result for query by ID for ID " + id);
}
if (res.size() > 1)
{
throw new DatabaseException("Inconsistent database! Multiple results for query by ID for ID " + id);
}
return res.get(0);
}
public static void delete_id(DbConn cnx, int id)
{
QueryResult res = cnx.runUpdate("ji_delete_by_id", id);
if (res.nbUpdated != 1)
{
throw new DatabaseException("Delete failed: row does not exist");
}
}
public static int enqueue(DbConn cnx, int queue_id, int job_id, String application, Integer parentId, String module, String keyword1,
String keyword2, String keyword3, String sessionId, String userName, String email, boolean highlander, Map<String, String> prms)
{
QueryResult qr = cnx.runUpdate("ji_insert_enqueue", email, application, keyword1, keyword2, keyword3, module, parentId, sessionId,
userName, job_id, queue_id, highlander);
int newId = qr.getGeneratedId();
if (prms != null)
{
for (Map.Entry<String, String> prm : prms.entrySet())
{
RuntimeParameter.create(cnx, newId, prm.getKey(), prm.getValue());
}
}
return newId;
}
}