/******************************************************************************
* Copyright (c) 2008 g-Eclipse consortium
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Initial development of the original code was made for
* project g-Eclipse founded by European Union
* project number: FP6-IST-034327 http://www.geclipse.eu/
*
* Contributor(s):
* Mariusz Wojtysiak - initial API and implementation
*
*****************************************************************************/
package eu.geclipse.core.jobs;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubMonitor;
import eu.geclipse.core.jobs.internal.Activator;
import eu.geclipse.core.jobs.internal.ParametricJobID;
import eu.geclipse.core.jobs.internal.ParametricJobStatus;
import eu.geclipse.core.model.GridModel;
import eu.geclipse.core.model.IGridContainer;
import eu.geclipse.core.model.IGridElement;
import eu.geclipse.core.model.IGridJob;
import eu.geclipse.core.model.IGridJobDescription;
import eu.geclipse.core.model.IGridJobID;
import eu.geclipse.core.model.IGridJobService;
import eu.geclipse.core.model.IGridJobStatus;
import eu.geclipse.core.model.IGridProject;
import eu.geclipse.core.model.IVirtualOrganization;
import eu.geclipse.core.reporting.ProblemException;
import eu.geclipse.jsdl.JSDLJobDescription;
import eu.geclipse.jsdl.parametric.IParametricJsdlGenerator;
import eu.geclipse.jsdl.parametric.ParametricGenerationCanceled;
import eu.geclipse.jsdl.parametric.ParametricJsdlException;
import eu.geclipse.jsdl.parametric.ParametricJsdlGeneratorFactory;
import eu.geclipse.jsdl.parametric.eclipse.ParametricJsdlSaver;
/**
* Job service, which handles parametric jobs. Can: submit parametric JSDL, update param job status, delete job
*/
public class ParametricJobService implements IGridJobService {
private IGridJobService jobService; // this service is valid only for job submission and may be null. Other methods delegates call to children of parametric job
private GridJob job; // parametric job, to which children all calls will be delegated
/**
* Constructor used only for job submission, when job is not known yet
* @param jobService
*/
public ParametricJobService( final IGridJobService jobService ) {
this.jobService = jobService;
}
/**
* Constructor used for submitted job, when parametric jobs is created and
* all actions are delegated to job children
* @param jobID
*/
public ParametricJobService( final ParametricJobID jobID ) {
this.job = jobID.getJob();
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridJobService#canSubmit(eu.geclipse.core.model.IGridJobDescription)
*/
public boolean canSubmit( final IGridJobDescription desc ) {
return this.jobService != null && this.jobService.canSubmit( desc );
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridJobService#deleteJob(eu.geclipse.core.model.IGridJob, org.eclipse.core.runtime.IProgressMonitor)
*/
public void deleteJob( final IGridJobID dummyJobId, final IVirtualOrganization vo, final IProgressMonitor monitor )
throws ProblemException
{
SubMonitor subMonitor = SubMonitor.convert( monitor );
List<GridJob> childrenJobs = getChildrenJobs();
subMonitor.setWorkRemaining( childrenJobs.size() );
for( GridJob gridJob : childrenJobs ) {
gridJob.deleteJob( subMonitor.newChild( 1 ) );
}
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridJobService#getJobStatus(eu.geclipse.core.model.IGridJobID, org.eclipse.core.runtime.IProgressMonitor)
*/
public IGridJobStatus getJobStatus( final IGridJobID id, final IVirtualOrganization vo, final boolean fullStatus, final IProgressMonitor progressMonitor ) throws ProblemException {
SubMonitor subMonitor = SubMonitor.convert( progressMonitor );
Set<String> statusNames = new HashSet<String>();
int statusType = IGridJobStatus.DONE;
List<GridJob> childrenJobs = getChildrenJobs();
subMonitor.setWorkRemaining( childrenJobs.size() );
boolean unkOccured = false, abortedOccured = false, runningOccured = false, waitingOccured = false, submittedOccured = false;
for( GridJob gridJob : childrenJobs ) {
subMonitor.subTask( String.format( Messages.getString("ParametricJobService.taskNameUpdating"), gridJob.getJobName() ) ); //$NON-NLS-1$
IGridJobStatus oldStatus = gridJob.getJobStatus();
IGridJobStatus jobStatus = gridJob.updateJobStatus( subMonitor.newChild( 1 ), fullStatus );
statusNames.add( jobStatus.getName() );
GridModel.getJobManager().jobStatusChanged( gridJob, oldStatus );
switch( jobStatus.getType() ) {
case IGridJobStatus.DONE:
break;
case IGridJobStatus.SUBMITTED:
submittedOccured = true;
break;
case IGridJobStatus.ABORTED:
abortedOccured = true;
break;
case IGridJobStatus.WAITING:
waitingOccured = true;
break;
case IGridJobStatus.RUNNING:
runningOccured = true;
break;
case IGridJobStatus.PURGED:
case IGridJobStatus.UNKNOWN:
case IGridJobStatus.UNDEF:
unkOccured = true;
break;
}
}
if( unkOccured ) {
statusType = IGridJobStatus.UNKNOWN;
} else if( abortedOccured ) {
statusType = IGridJobStatus.ABORTED;
} else if( submittedOccured ) {
statusType = IGridJobStatus.SUBMITTED;
} else if( waitingOccured ) {
statusType = IGridJobStatus.WAITING;
} else if( runningOccured ) {
statusType = IGridJobStatus.RUNNING;
} else {
statusType = IGridJobStatus.DONE;
}
return new ParametricJobStatus( statusNames.toString(), statusType, childrenJobs );
}
private List<GridJob> getChildrenJobs() throws ProblemException {
IGridElement[] children = this.job.getChildren( new NullProgressMonitor() );
List<GridJob> childrenJobs = new ArrayList<GridJob>( children.length );
for( IGridElement gridElement : children ) {
if( gridElement instanceof GridJob ) {
childrenJobs.add( ( GridJob )gridElement );
}
}
return childrenJobs;
}
/**
* @param jsdl
* @param parent
* @param jobName
* @return created job
* @throws ProblemException
*/
public IGridJob createParamJobStructure( final JSDLJobDescription jsdl,
final IGridContainer parent,
final String jobName )
throws ProblemException
{
ParametricJobID jobId = new ParametricJobID();
GridJobCreator creator = new GridJobCreator();
creator.canCreate( jsdl );
return creator.create( parent, jobId, this, jobName );
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridJobService#submitJob(eu.geclipse.core.model.IGridJobDescription, org.eclipse.core.runtime.IProgressMonitor)
*/
/**
* Specialized method to submit parametric job
* @param description
* @param monitor
* @param parent
* @param jobName
* @return submitted job
* @throws ProblemException
*/
public IGridJobID submitJob( final IGridJobDescription description,
final SubMonitor monitor, final IGridContainer parent, final String jobName )
throws ProblemException
{
IGridJobID jobId = null;
SubMonitor subMonitor = SubMonitor.convert( monitor );
Assert.isTrue( description instanceof JSDLJobDescription );
JSDLJobDescription jsdl = ( JSDLJobDescription )description;
if( isResumedSubmition( jsdl ) ) {
jobId = resumeSubmission( jsdl, subMonitor );
} else {
Assert.isTrue( jsdl.isParametric() );
subMonitor.setWorkRemaining( 10 );
subMonitor.subTask( Messages.getString("ParametricJobService.taskNameGeneratingJsdl") ); //$NON-NLS-1$
IGridJob parametricGridJob = createParamJobStructure( jsdl, parent, jobName );
IParametricJsdlGenerator generator = ParametricJsdlGeneratorFactory.getGenerator( jsdl.getAsString() );
IFolder generationTargetfolder = ((IFolder)parametricGridJob.getResource()).getFolder( Messages.getString("ParametricJobService.generatedJsdlFolder") ); //$NON-NLS-1$
ParametricJsdlSaver saver = new ParametricJsdlSaver( jsdl, generationTargetfolder, subMonitor.newChild( 1 ) );
try {
generator.generate( saver );
} catch( ParametricGenerationCanceled exception ) {
throw new OperationCanceledException();
} catch( ParametricJsdlException exception ) {
throw new ProblemException( "eu.geclipse.core.jobs.problem.generateParamJsdlFailed", exception, Activator.PLUGIN_ID ); //$NON-NLS-1$
}
List<JSDLJobDescription> generatedJsdls = saver.getGeneratedJsdl();
submitGeneratedJsdl( parametricGridJob, generatedJsdls, subMonitor.newChild( 9 ), jobName );
cleanupSubmission( generationTargetfolder );
jobId = new ParametricJobID();
}
return jobId;
}
private IGridJobID resumeSubmission( final JSDLJobDescription jsdl, final SubMonitor monitor ) throws ProblemException {
GridJob parentJob = findParentParamJob( jsdl );
Assert.isNotNull( parentJob );
List<JSDLJobDescription> jsdlList = new ArrayList<JSDLJobDescription>( 1 );
jsdlList.add( jsdl );
submitGeneratedJsdl( parentJob, jsdlList, monitor, parentJob.getJobName() );
cleanupSubmission( ( IFolder )jsdl.getResource().getParent() );
return parentJob.getID();
}
private boolean isResumedSubmition( final JSDLJobDescription jsdl ) {
return findParentParamJob( jsdl ) != null;
}
private GridJob findParentParamJob( final JSDLJobDescription jsdl ) {
GridJob paramJob = null;
if( !jsdl.isParametric() ) {
IGridContainer parent = jsdl.getParent();
while( parent != null ) {
if( parent instanceof GridJob ) {
GridJob parentJob = ( GridJob )parent;
IGridJobDescription parentDescription = parentJob.getJobDescription();
if( parentDescription instanceof JSDLJobDescription
&& (( JSDLJobDescription )parentDescription).isParametric() ) {
paramJob = parentJob;
}
break;
}
parent = parent.getParent();
}
}
return paramJob;
}
private void cleanupSubmission( final IFolder generationTargetfolder ) throws ProblemException {
try {
if( generationTargetfolder.members().length == 0 ) {
generationTargetfolder.delete( true, null );
}
} catch ( CoreException exception ) {
throw new ProblemException( "eu.geclipse.core.jobs.problem.cleanupSubmissionFailed", exception, Activator.PLUGIN_ID ); //$NON-NLS-1$
}
}
private List<IGridJobID> submitGeneratedJsdl( final IGridJob parametricJob, final List<JSDLJobDescription> generatedJsdls,
final SubMonitor monitor, final String jobName ) throws ProblemException
{
List<IGridJobID> submittedJobs = new ArrayList<IGridJobID>( generatedJsdls.size() );
GridJobCreator jobCreator = new GridJobCreator();
monitor.setWorkRemaining( generatedJsdls.size() );
for ( JSDLJobDescription jobDescription : generatedJsdls ) {
String subjobName = getSubJobName( jobDescription, jobName );
testCancelled( monitor );
monitor.setTaskName( String.format( Messages.getString("ParametricJobService.taskSubmitting"), jobDescription.getName() ) ); //$NON-NLS-1$
IGridJobID jobID = this.jobService.submitJob( jobDescription, monitor.newChild( 1 ) );
submittedJobs.add( jobID );
testCancelled( monitor );
jobCreator.canCreate( jobDescription );
jobCreator.create( parametricJob, jobID, this.jobService, subjobName );
try {
jobDescription.getResource().delete( true, monitor.newChild( 0 ) );
} catch( CoreException exception ) {
throw new ProblemException( "eu.geclipse.core.jobs.problem.deleteGeneratedJsdlFailed", exception, Activator.PLUGIN_ID ); //$NON-NLS-1$
}
}
return submittedJobs;
}
private String getSubJobName( final JSDLJobDescription jobDescription,
final String jobName )
{
String subJobName = jobName;
String jsdlName = new Path( jobDescription.getName() ).removeFileExtension().toString();
int suffixIndex = jsdlName.indexOf( '[' );
if( suffixIndex > -1 ) {
subJobName = jobName + jsdlName.substring( suffixIndex );
}
return subJobName;
}
private void testCancelled( final SubMonitor monitor ) {
if( monitor.isCanceled() ) {
throw new OperationCanceledException();
}
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridResource#getHostName()
*/
public String getHostName() {
return this.jobService != null ? this.jobService.getHostName() : Messages.getString("ParametricJobService.unknownHostName"); //$NON-NLS-1$
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridResource#getURI()
*/
public URI getURI() {
return this.jobService != null ? this.jobService.getURI() : null;
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridElement#dispose()
*/
public void dispose() {
if( this.jobService != null ) {
this.jobService.dispose();
}
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridElement#getFileStore()
*/
public IFileStore getFileStore() {
return this.jobService.getFileStore();
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridElement#getName()
*/
public String getName() {
return this.jobService.getName();
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridElement#getParent()
*/
public IGridContainer getParent() {
return this.jobService.getParent();
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridElement#getPath()
*/
public IPath getPath() {
return this.jobService.getPath();
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridElement#getProject()
*/
public IGridProject getProject() {
return this.jobService != null ? this.jobService.getProject() : null;
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridElement#getResource()
*/
public IResource getResource() {
return this.jobService.getResource();
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridElement#isHidden()
*/
public boolean isHidden() {
return this.jobService.isHidden();
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridElement#isLocal()
*/
public boolean isLocal() {
return this.jobService.isLocal();
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridElement#isVirtual()
*/
public boolean isVirtual() {
return this.jobService.isVirtual();
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
@SuppressWarnings("unchecked")
public Object getAdapter( final Class adapter ) {
return this.jobService != null ? this.jobService.getAdapter( adapter ) : null;
}
public IGridJobID submitJob( final IGridJobDescription description,
final IProgressMonitor monitor )
throws ProblemException
{
String msg = "ParametricJobService can submit only parametric JSDLs"; //$NON-NLS-1$
throw new ProblemException( "eu.geclipse.core.jobs.problem.unsupportedOperation", msg, Activator.PLUGIN_ID ); //$NON-NLS-1$
}
public IGridJobID submitJob( final IGridJobDescription description,
final IVirtualOrganization vo,
final IProgressMonitor monitor )
throws ProblemException
{
String msg = "ParametricJobService can submit only parametric JSDLs"; //$NON-NLS-1$
throw new ProblemException( "eu.geclipse.core.jobs.problem.unsupportedOperation", msg, Activator.PLUGIN_ID ); //$NON-NLS-1$
}
public Map<String, URI> getInputFiles( final IGridJobID jobId,
final IGridJobDescription jobDescription,
final IVirtualOrganization vo )
throws ProblemException
{
return null;
}
public Map<String, URI> getOutputFiles( final IGridJobID jobId,
final IGridJobDescription jobDescription,
final IVirtualOrganization vo )
throws ProblemException
{
return null;
}
}