it.infn.ct.futuregateway.apiserver.resources.Task.java Source code

Java tutorial

Introduction

Here is the source code for it.infn.ct.futuregateway.apiserver.resources.Task.java

Source

/**
 * *********************************************************************
 * Copyright (c) 2015: Istituto Nazionale di Fisica Nucleare (INFN), Italy
 * Consorzio COMETA (COMETA), Italy
 *
 * See http://www.infn.it and and http://www.consorzio-cometa.it for details on
 * the copyright holders.
 *
 * 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 it.infn.ct.futuregateway.apiserver.resources;

import it.infn.ct.futuregateway.apiserver.utils.LinkJaxbAdapter;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Observable;
import java.util.Random;
import java.util.UUID;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.Transient;
import javax.ws.rs.core.Link;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.collections4.Predicate;
import org.glassfish.jersey.linking.InjectLink;
import org.glassfish.jersey.linking.InjectLinks;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

/**
 * The Task represents any activity a user send to an infrastructure, such as a
 * run a job in a grid computing site or deploy a VM in a cloud.
 *
 * @author Marco Fargetta <marco.fargetta@ct.infn.it>
 */
@NamedQueries({
        @NamedQuery(name = "tasks.userAll", query = "SELECT t.id, t.description, t.status, t.dateCreated"
                + " FROM Task t WHERE t.userName = :user"),
        @NamedQuery(name = "tasks.forApplication", query = "SELECT t.id FROM Task t WHERE "
                + "t.applicationDetail.id = :appId") })
@Entity
@Table(name = "Task")

@InjectLinks({ @InjectLink(value = "tasks/{id}", rel = "self"),
        @InjectLink(value = "tasks/{id}/input", rel = "input") })

@XmlRootElement(name = "task")
@XmlAccessorType(XmlAccessType.FIELD)
public class Task extends Observable implements Serializable {

    /**
     * Possible status for the task.
     */
    public enum STATUS {

        /**
         * Task created but input still required.
         */
        WAITING,
        /**
         * Task ready to be scheduled to the infrastructure.
         */
        READY,
        /**
         * Task ready to execute in the selected infrastructure.
         */
        SCHEDULED,
        /**
         * In execution.
         */
        RUNNING,
        /**
         * Task completed.
         */
        DONE,
        /**
         * Some error prevent the task from the execution.
         */
        ABORTED,
        /**
         * Task deleted by the user.
         */
        CANCELLED
    };

    /**
     * List of references.
     */
    @InjectLinks({ @InjectLink(value = "tasks/{id}", rel = "self"),
            @InjectLink(value = "tasks/{id}/input", rel = "input") })
    @XmlElement(name = "_links")
    @XmlJavaTypeAdapter(value = LinkJaxbAdapter.class)
    private List<Link> links;

    /**
     * The identifier of the task.
     */
    @XmlElement(name = "id")
    private String id;

    /**
     * The id of the application associated with the task.
     */
    @XmlElement(name = "application")
    private String applicationId;

    /**
     * The id of the application associated with the task.
     */
    @XmlTransient
    private Application applicationDetail;

    /**
     * A user provided description of the task.
     */
    private String description;

    /**
     * Arguments to provide to the application.
     */
    private List<String> arguments;

    /**
     * Arguments to provide to the application.
     */
    @XmlElement(name = "output_files")
    private List<TaskFileOutput> outputFiles;

    /**
     * Input file for the application.
     */
    @XmlElement(name = "input_files")
    private List<TaskFileInput> inputFiles;

    /**
     * The current status of the task.
     */
    private STATUS status;

    /**
     * The date when the task was created.
     */
    @XmlElement(name = "runtime_data")
    private List<RuntimeParams> runtime;

    /**
     * The user name submitting the task.
     */
    @XmlElement(name = "user")
    private String userName;

    /**
     * The date when the task was created.
     */
    @XmlElement(name = "date")
    private Date dateCreated;

    /**
     * The date of last task status update.
     */
    @XmlElement(name = "last_change")
    private Date lastChange;

    /**
     * Infrastructure executing the task.
     * An application can be associated with multiple infrastructure, this is
     * the Id of one selected to execute the task.
     */
    @XmlTransient
    private String associatedInfrastructureId;

    /**
     * Native id.
     * The id associated with the task by the infrastructure. This is the
     * identifier used to communicate with the remote infrastructure to monitor
     * the task and/or retrieve the output.
     */
    @XmlTransient
    private String nativeId;

    /**
     * Retrieve the task identifier.
     *
     * @return The identifier of this task
     */
    @Id
    @Column(name = "id")
    public String getId() {
        return id;
    }

    /**
     * Sets the task identifier.
     *
     * @param anId The task identifier
     */
    public void setId(final String anId) {
        this.id = anId;
        setChanged();
        notifyObservers();
    }

    /**
     * Initialise the id.
     *
     * The id for the task is generated with a random uuid. There is not a
     * collision control at this level. If the persistence failed because of
     * this Id is repeated the code at higher level should manage the situation
     * by replacing the Id.
     */
    @PrePersist
    private void generateId() {
        if (this.id == null || this.id.isEmpty()) {
            this.id = UUID.randomUUID().toString();
        }
    }

    /**
     * Returns the associated application.
     *
     * @return The id of the application associated with the task
     */
    @ManyToOne(optional = false, fetch = FetchType.EAGER)
    @JoinColumn(name = "applicationId", referencedColumnName = "id", nullable = false)
    public Application getApplicationDetail() {
        return applicationDetail;
    }

    /**
     * Sets the application to associate with the task.
     * The application has to be valid in order the task to be valid.
     *
     * @param anApplication The application identifier
     */
    public void setApplicationDetail(final Application anApplication) {
        this.applicationDetail = anApplication;
        if (applicationId == null) {
            applicationId = applicationDetail.getId();
        }
        lastChange = new Date();
        setChanged();
        notifyObservers();
    }

    /**
     * Returns the id of the associated application.
     *
     * @return The id of the application associated with the task
     */
    @Transient
    public String getApplicationId() {
        if (applicationId == null && applicationDetail != null) {
            applicationId = applicationDetail.getId();
        }
        return applicationId;
    }

    /**
     * Sets the application to associate with the task.
     * The application has to be valid in order the task to be valid.
     *
     * @param anApplication The application identifier
     */
    public void setApplicationId(final String anApplication) {
        this.applicationId = anApplication;
        lastChange = new Date();
        setChanged();
    }

    /**
     * Returns the user description of the task.
     *
     * @return The user description
     */
    public String getDescription() {
        return description;
    }

    /**
     * Sets a description for the task.
     *
     * @param aDescription Task description
     */
    public void setDescription(final String aDescription) {
        this.description = aDescription;
        lastChange = new Date();
        setChanged();
    }

    /**
     * Retrieve the list of arguments for the application. This is a list of
     * string the system will use as parameter for the application. Actually,
     * the list will be converted in a space separated string maintaining the
     * order of the list.
     * <p>
     * The use of the list will depend on the application. In case of an
     * executable the list will be appended to the command line but for a
     * service there is not a standard use at the moment.
     *
     * @return The list of arguments
     */
    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "application_arguments", joinColumns = @JoinColumn(name = "id"))
    @Column(name = "arguments")
    public List<String> getArguments() {
        return arguments;
    }

    /**
     * Sets a list of arguments for the application. This is a list of string
     * the system will use as parameter for the application. Actually, the list
     * will be converted in a space separated string maintaining the order of
     * the list.
     * <p>
     * The use of the list will depend on the application. In case of an
     * executable the list will be appended to the command line but for a
     * service there is not a standard use at the moment.
     *
     * @param someArguments The arguments to provide to the application
     */
    public void setArguments(final List<String> someArguments) {
        this.arguments = someArguments;
        lastChange = new Date();
        setChanged();
    }

    /**
     * Retrieve the list of output files of the application. This is the list of
     * files the system has to retrieve after the application or the service has
     * completed its execution.
     *
     * @return The output files
     */
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT)
    public List<TaskFileOutput> getOutputFiles() {
        return this.outputFiles;
    }

    /**
     * Sets the list of output files of the application. This is the list of
     * files the system has to retrieve after the application or the service has
     * completed its execution.
     *
     * @param someOutputFiles A list with the output files
     */
    public void setOutputFiles(final List<TaskFileOutput> someOutputFiles) {
        this.outputFiles = someOutputFiles;
        lastChange = new Date();
        setChanged();
    }

    /**
     * Retrieve the input files for the application. This is a map of files sent
     * to the remote infrastructure for the execution of the application and/or
     * service. The map key is the file name and the map value is an URL
     * locating the file.
     * <p>
     * The URL can be local or remote to the service.
     *
     * @return The input files
     */
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT)
    public List<TaskFileInput> getInputFiles() {
        return this.inputFiles;
    }

    /**
     * Sets the input files for the application. This is a map of files sent to
     * the remote infrastructure for the execution of the application and/or
     * service. The map key is the file name and the map value is an URL
     * locating the file.
     * <p>
     * The URL can be local or remote to the service.
     *
     * @param someInputFiles A map with the input files.
     */
    public void setInputFiles(final List<TaskFileInput> someInputFiles) {
        this.inputFiles = someInputFiles;
        lastChange = new Date();
        setChanged();
    }

    /**
     * Returns the status of the task.
     *
     * @return The status.
     * @see it.infn.ct.futuregateway.apiserver.v1.resources.Task.STATUS
     */
    @Enumerated(EnumType.STRING)
    public STATUS getStatus() {
        return status;
    }

    /**
     * Sets the status for the task.
     *
     * @param aStatus The status to associate with the task
     * @see it.infn.ct.futuregateway.apiserver.v1.resources.Task.STATUS
     */
    public void setStatus(final STATUS aStatus) {
        lastChange = new Date();
        setChanged();
        this.status = aStatus;
        notifyObservers();
    }

    /**
     * Returns the runtime information.
     * Runtime information are retrieved by the system during the submission and
     * or execution of the task and can be relevant to the user. E.g. in case of
     * task running a VM the relevant information could be the IP and the
     * credentials of the machine.
     *
     * @return List of runtime
     */
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT)
    public List<RuntimeParams> getRuntime() {
        return runtime;
    }

    /**
     * Sets the runtime information.
     * Runtime information are retrieved by the system during the submission and
     * or execution of the task and can be relevant to the user. E.g. in case of
     * task running a VM the relevant information could be the IP and the
     * credentials of the machine.
     *
     * @param someRuntime A list of runtime parameters
     */
    public void setRuntime(final List<RuntimeParams> someRuntime) {
        lastChange = new Date();
        setChanged();
        this.runtime = someRuntime;
        notifyObservers();
    }

    /**
     * Returns the user identifier. Every task is associated to a user. The
     * identifier is provided by an external entity (e.g. a Web Application) and
     * can be of any kind but has to be unique for the user.
     *
     * @return The user identifier
     */
    public String getUserName() {
        return userName;
    }

    /**
     * Sets the user identifier. Every task is associated to a user. The
     * identifier is provided by an external entity (e.g. a Web Application) and
     * can be of any kind but has to be unique for the user.
     *
     * @param aUser The user identifier
     */
    public void setUserName(final String aUser) {
        this.userName = aUser;
        lastChange = new Date();
        setChanged();
    }

    /**
     * Returns the creation time of the task.
     *
     * @return Creation time
     */
    @Temporal(javax.persistence.TemporalType.TIMESTAMP)
    public Date getDateCreated() {
        return dateCreated;
    }

    /**
     * Sets the creation time of the task.
     *
     * @param creationDate The creation time
     */
    public void setDateCreated(final Date creationDate) {
        this.dateCreated = creationDate;
        lastChange = new Date();
        setChanged();
    }

    /**
     * Returns the time of last status change.
     *
     * @return The time of last status change
     */
    @Temporal(javax.persistence.TemporalType.TIMESTAMP)
    public Date getLastChange() {
        return lastChange;
    }

    /**
     * Sets the time of last status change.
     *
     * @param newChangeDate The time of last status change
     */
    public void setLastChange(final Date newChangeDate) {
        this.lastChange = newChangeDate;
        lastChange = new Date();
        setChanged();
    }

    /**
     * Returns the references for this entity.
     *
     * @return The list of Link references
     */
    @Transient
    public List<Link> getLinks() {
        return links;
    }

    /**
     * Sets the references for this entity.
     *
     * @param someLinks The list of link references
     */
    public void setLinks(final List<Link> someLinks) {
        this.links = someLinks;
        lastChange = new Date();
        setChanged();
    }

    /**
     * Retrieves the associated infrastructure Id.
     * This is the infrastructure selected to execute the task among
     * the many the application can run on.
     *
     * @return The infrastructure
     */
    @Transient
    public Infrastructure getAssociatedInfrastructure() {
        if (applicationDetail == null) {
            return null;
        }
        return IterableUtils.find(applicationDetail.getInfrastructures(), new Predicate<Infrastructure>() {
            @Override
            public boolean evaluate(final Infrastructure t) {
                return t.getId().equals(getAssociatedInfrastructureId());
            }
        });
    }

    /**
     * Retrieves the associated infrastructure Id.
     * This is the Id of the infrastructure selected to execute the task among
     * the many the application can run on.
     *
     * @return The infrastructure Id
     */
    public String getAssociatedInfrastructureId() {
        if ((associatedInfrastructureId == null || associatedInfrastructureId.isEmpty())
                && applicationDetail != null) {
            List<Infrastructure> infras = ListUtils.select(applicationDetail.getInfrastructures(),
                    new Predicate<Infrastructure>() {
                        @Override
                        public boolean evaluate(final Infrastructure t) {
                            return t.isEnabled();
                        }
                    });
            Random rand = new Random((new Date()).getTime());

            while (!infras.isEmpty()) {
                Infrastructure i = infras.remove(rand.nextInt(infras.size()));
                if (i.isEnabled()) {
                    setAssociatedInfrastructureId(i.getId());
                    return associatedInfrastructureId;
                }
            }
        }
        return associatedInfrastructureId;
    }

    /**
     * Sets the infrastructure for the execution.
     * It has to be one of the infrastructure the application is enabled to
     * execute.
     *
     * @param anInfrastructure The infrastructure Id
     */
    public void setAssociatedInfrastructureId(final String anInfrastructure) {
        this.associatedInfrastructureId = anInfrastructure;
        lastChange = new Date();
        setChanged();
        notifyObservers();
    }

    /**
     * Retrieves the Identifier generated in the remote infrastructure.
     * @return The Id
     */
    public String getNativeId() {
        return nativeId;
    }

    /**
     * Sets the Identifier generated in the remote infrastructure.
     *
     * @param aNativeId The Id
     */
    public void setNativeId(final String aNativeId) {
        this.nativeId = aNativeId;
        setChanged();
        notifyObservers();
    }

    /**
     * Update the status of input files.
     * Change the status value for the input file specified. If the name is not
     * associated with any input file nothing happen.
     * <p>
     * There is not check on the file existence and real status which
     * is delegated to the caller object.
     *
     * @param name File name
     * @param aStatus New status
     */
    public final void updateInputFileStatus(final String name, final TaskFile.FILESTATUS aStatus) {

        TaskFileInput tfi = IterableUtils.find(inputFiles, new Predicate<TaskFileInput>() {
            @Override
            public boolean evaluate(final TaskFileInput t) {
                return t.getName().equals(name);
            }
        });
        if (tfi != null) {
            tfi.setStatus(aStatus);
            lastChange = new Date();
            setChanged();
            notifyObservers();
        }
    }
}