GridLab
Grid Application Toolkit

A simple API for Grid Applications
GAT

Menu



Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members  

GATJob.c

Go to the documentation of this file.
00001 /** @file GATJob.c
00002  *  Source file for the GATJob class.
00003  *
00004  *  A GATJob represents one or more processes which are running or may be 
00005  *  submitted to a resource management system, e.g. by a globusrun command.
00006  * 
00007  *  @date Thu Oct 23 2003
00008  *
00009  *  @version $Header: /export/cvs-gridlab/wp-1/Codes/GATEngine/C-reference/src/GATJob.c,v 1.24 2004/05/12 18:56:00 hartmutkaiser Exp $
00010  *
00011  *  Copyright (C) Hartmut Kaiser
00012  *  This file is part of the GAT Engine.
00013  *  Contributed by Hartmut Kaiser <hartmutkaiser [at] t-online [dot] de>.
00014  *
00015  *  Use, modification and distribution is subject to the Gridlab Software
00016  *  License. (See accompanying file GLlicense.txt or copy at
00017  *  http://www.gridlab.org/GLlicense.txt)
00018  */
00019 
00020 static const char *rcsid = "$Header: /export/cvs-gridlab/wp-1/Codes/GATEngine/C-reference/src/GATJob.c,v 1.24 2004/05/12 18:56:00 hartmutkaiser Exp $";
00021  
00022 /* System Header objects */
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <assert.h>
00026 
00027 /* GAT Header objects */
00028 #include "GAT.h"
00029 #include "GATInternal.h"
00030 #include "GATRegistry.h"
00031 #include "GATJobCPI.h"
00032 #include "GATXdsWrapper.h"
00033 #include "GATMetricEvent.h"
00034 
00035 /* define the vtable types */
00036 GATOBJECT_DEFINE_VTABLE(GATJob);
00037 GATSERIALISABLE_DEFINE_VTABLE(GATJob);
00038 GATMONITORABLE_DEFINE_VTABLE(GATJob);
00039 
00040 /* define the converters to/from GATObject */
00041 GATOBJECT_DEFINE_CONVERTERS(GATJob)
00042 
00043 /* Macros */
00044 
00045 /* Structures, unions and enums */
00046 struct GATJob_S {
00047   /* supported interfaces */
00048   GATJob_vtable *GATObject__vtable;
00049   GATJob_ISerialisable_vtable *GATSerialisable__vtable;
00050   GATJob_IMonitorable_vtable *GATMonitorable__vtable;
00051 
00052   /* instance data */
00053   GATJobID gatjobid;       /* the GAT job id */
00054   
00055   GATJobCPI_Instance data; /* instance data of the corresponding CPI object */
00056   GATJobCPI cpi;         /* CPI object to use for all subsequent operations */
00057   GATJobCPIList cpilist; /* CPI list of appropriate CPI objects */
00058 };
00059 
00060 /* Static function prototypes */
00061 static GATResult
00062 GATJob_DeSerialise_Create(GATContext context, GATObject stream, GATJobID jobid,
00063   GATJobState state, GATJob *new_object);
00064 
00065 static GATResult
00066 GATJob_GetCPIInstanceData(GATJob job, void **data);
00067 
00068 
00069 /* file scope variables */
00070 GATJob_vtable GATJob__vtable = {
00071   GATJob_GetType,
00072   GATJob_Destroy,
00073   GATJob_Equals,
00074   GATJob_Clone,
00075   GATJob_GetInterface,
00076   GATJob_GetCPIInstanceData
00077 };
00078 
00079 static GATJob_ISerialisable_vtable 
00080   GATJob_ISerialisable__vtable = 
00081 {
00082   GATJob_Serialise,
00083   GATJob_DeSerialise,
00084   GATJob_GetIsDirty,
00085 };
00086 
00087 static GATJob_IMonitorable_vtable 
00088   GATJob_IMonitorable__vtable = 
00089 {
00090   GATJob_AddMetricListener,
00091   GATJob_RegisterPolling,
00092   GATJob_RemoveRegisteredMetric,
00093   GATJob_GetMetrics
00094 };
00095 
00096 /* External functions */
00097 
00098 /** GATJob_Register_GATSerialisable
00099  *  The GATJob_Register_GATSerialisable function registers the serialization
00100  *  vtable with the GAT engine to allow generic object creation.
00101  *  This function is called by the GAT engine, there is no need to use it 
00102  *  directly.
00103  */
00104 GATResult GATJob_Register_GATSerialisable(void)
00105 {
00106   return GATObject_Register_GATSerialisable(GATType_GATJob, 
00107     &GATJob_ISerialisable__vtable);
00108 }
00109 
00110 /** GATJob_Create
00111  *  @brief Create a new GATJob object
00112  *
00113  *  The function @c GATJob_Create creates a new 
00114  *  GATJob object
00115  *
00116  *  @param context The GAT context to use while the initialisation of the 
00117  *        new object.
00118  *  @param preferences The preferences to use while selecting the adaptor for 
00119  *        the corresponding CPI.
00120  *  @param jobid The job id of the new job, which was assigned by the resource 
00121  *        management system, which cretaed this job.
00122  *  @param initialisation_data This is the data to be used to initialise the 
00123  *        internal job instance data. The type of this data is defined by the
00124  *        adaptor creating this job. This data is handed byck to the adaptor
00125  *        during job construction.
00126  *
00127  *  @return Returns a handle to the newly created GATJob object.
00128  *        Returns 0 (zero) if an error occurs.
00129  */
00130 GATJob 
00131 GATJob_Create(GATContext context, GATPreferences_const preferences, GATJobID jobid,
00132   void *initialisation_data)
00133 {
00134   GAT_STATUS_APIENTRY(context, "GATJob_Create");
00135   
00136   GATJob retval = (GATJob) malloc(sizeof(struct GATJob_S));
00137   if (NULL != retval)
00138   {
00139     memset(retval, 0, sizeof(struct GATJob_S));
00140     retval->GATObject__vtable = &GATJob__vtable;
00141     retval->GATSerialisable__vtable = &GATJob_ISerialisable__vtable;
00142     retval->GATMonitorable__vtable = &GATJob_IMonitorable__vtable;
00143 
00144     retval->gatjobid = NULL;          /* should be set later */
00145     retval->data.context = context;
00146     retval->data.isdirty = GATFalse;
00147     retval->data.source = GATJob_ToGATObject_const(retval);
00148     retval->data.state = GATJobState_Initial;
00149 
00150     GAT_CREATE_STATUS(GATString_Clone(jobid, &retval->data.jobid));
00151     
00152     /* find a CPI object, which can handle this object */
00153     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS())) 
00154     {
00155       GATRegistry_const registry = GATContext_internal_GetRegistry(context);
00156       
00157       /* use default preferences, if appropriate */
00158       if (NULL == preferences)
00159       {
00160         preferences = GATContext_GetPreferences(context);
00161       }
00162       retval->cpilist = GATRegistry_FindGATJobCPI(registry, preferences);
00163       
00164       if (NULL == retval->cpilist)
00165       {
00166         GAT_CREATE_STATUS(GAT_NO_REGISTERED_CPI);
00167       }
00168       else 
00169       {
00170         /* create a new instance of the CPI provider */
00171         GATBool found_cpi = GATFalse;
00172         GATJobCPIList current = NULL;
00173         for(current = retval->cpilist; NULL != current; current = current->next)
00174         {
00175           GAT_CREATE_STATUS(GATJobCPI_CreateInstance(current->cpi, 
00176             &retval->data, initialisation_data));
00177             
00178           if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00179           {
00180             retval->cpi = current->cpi;
00181             found_cpi = GATTrue;
00182             break;
00183           }
00184         }
00185 
00186         /* no available CPI object can handle this */
00187         if (GATFalse == found_cpi)
00188         {
00189           GAT_CREATE_STATUS(GAT_NO_REGISTERED_CPI);
00190         }
00191         else
00192         {
00193           /* now, initialise the monitoring framework with the help of the
00194              CPI provider found */
00195           GATList_GATMetric metrics = NULL;
00196           GATResult err_code = GATJobCPI_GetMetrics(retval->cpi, 
00197             &retval->data, &metrics);            
00198 
00199           if (GAT_SUCCEEDED(err_code))
00200           {
00201             retval->data.monitorable = GATMonitorable_Impl_Create(metrics);
00202             if (NULL == retval->data.monitorable)
00203             {
00204               GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00205             }
00206             GATList_GATMetric_Destroy(&metrics);
00207           }
00208           else if (GAT_NOTIMPL == err_code)
00209           {
00210             err_code = GAT_SUCCESS;   /* no monitoring supported here */
00211           }
00212           else
00213           {
00214             GAT_CREATE_STATUS(err_code);
00215           }
00216 
00217           /* register this object with the engine */
00218           if (GAT_SUCCEEDED(err_code))
00219           {
00220             GAT_CREATE_STATUS(GATRegistry_AddGATJobToCPIList(context, retval->cpi, 
00221               retval));
00222           }
00223         }
00224       }
00225     }
00226   }
00227   else
00228   {
00229     GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00230   }
00231 
00232   /* error handling */
00233   if (GAT_FAILED(GAT_CURRENT_STATUS()))
00234   {
00235     GATJob_Destroy(&retval);
00236   }
00237 
00238   GAT_STORE_STATUS();
00239   return retval;
00240 }
00241 
00242 /** void GATJob_Destroy(GATJob *resource)
00243  *
00244  *  The function GATJob_Destroy is the destructor used to
00245  *  free all the memory allocated by an GATJob instance.
00246  *
00247  *  @param description The pointer to the GATJob to destroy
00248  */
00249 void
00250 GATJob_Destroy(GATJob *object)
00251 {
00252   if (NULL != object && NULL != *object)
00253   {
00254     GATString_Destroy(&(*object)->gatjobid);
00255     GATString_Destroy(&(*object)->data.jobid);
00256     GATMonitorable_Impl_Destroy(&(*object)->data.monitorable);
00257     if (NULL != (*object)->cpi)  /* during creation this may be zero */
00258     {
00259       GATRegistry_RemoveGATJobFromCPIList((*object)->data.context, 
00260         (*object)->cpi, *object);
00261       GATJobCPI_DestroyInstance((*object)->cpi, &(*object)->data);
00262     }
00263     GATJobCPIList_Destroy((*object)->cpilist);
00264     free(*object);
00265     *object = NULL;
00266   }
00267 }
00268 
00269 /** GATJob_Equals
00270  *  @brief Compare two GATJob objects
00271  *
00272  *  The function @c GATJob_Equals compares two objects of the
00273  *  @c GATJob type.
00274  *
00275  *  @param lhs The first list to compare
00276  *  @param rhs The second list to compare
00277  *  @param isequal The pointer to the GATBool variable, which should receive 
00278  *        the result if the comparision
00279  *
00280  *  @return An error code.
00281  */
00282 GATResult 
00283 GATJob_Equals(GATJob_const lhs, GATJob_const rhs, GATBool *isequal)
00284 {
00285   if (NULL != lhs && NULL != rhs)
00286   {
00287     GAT_STATUS_APIENTRY(lhs->data.context, "GATJob_Equals");
00288     if (NULL != isequal)
00289     {
00290       if (lhs->data.state != rhs->data.state)
00291       {
00292         *isequal = GATFalse;
00293       }
00294       else
00295       {
00296         GAT_CREATE_STATUS(GATJobCPI_EqualsInstance(lhs->cpi, &lhs->data, 
00297           &rhs->data, isequal));
00298       }
00299     }
00300     return GAT_RETURN_STATUS();
00301   }
00302   return GAT_INVALID_HANDLE;
00303 }
00304 
00305 /** GATJob_Clone
00306  *  @brief Clone the given GATJob
00307  *
00308  *  The function @c GATJob_Clone generates a (deep) copy of 
00309  *  the given GATJob. 
00310  *
00311  *  @param description The object to clone
00312  *  @param new_object The pointer, through which the result is to be 
00313  *        returned.
00314  *
00315  *  @return An error type.
00316  */
00317 GATResult 
00318 GATJob_Clone(GATJob_const handle, GATJob *new_handle)
00319 {
00320   if (NULL != handle)
00321   {
00322     GAT_STATUS_APIENTRY(handle->data.context, "GATJob_Clone");
00323     
00324     if (NULL == new_handle)
00325     {
00326       GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
00327     }
00328     else
00329     {
00330       struct GATJob_S const *object = handle;
00331       GATJob new_object = (GATJob) malloc(sizeof(struct GATJob_S));
00332       
00333       *new_handle = NULL;
00334       if (NULL == new_object)
00335       {
00336         GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00337       }
00338       else
00339       {
00340         memset(new_object, 0, sizeof(struct GATJob_S));
00341         new_object->GATObject__vtable = &GATJob__vtable;
00342         new_object->GATSerialisable__vtable = &GATJob_ISerialisable__vtable;
00343         new_object->GATMonitorable__vtable = &GATJob_IMonitorable__vtable;
00344 
00345         new_object->data.context = object->data.context;
00346         new_object->data.isdirty = GATFalse;
00347         new_object->data.source = GATJob_ToGATObject_const(new_object);
00348         new_object->data.state = object->data.state;
00349         new_object->cpilist = GATRegistry_CloneGATJobCPIList(object->cpilist);
00350 
00351         if (NULL == new_object->cpilist)
00352         {
00353           GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00354         }
00355         GAT_CREATE_STATUS(GATString_Clone(object->data.jobid, 
00356           &new_object->data.jobid));
00357 
00358         if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00359         {
00360           /* re-find the cpi to use */
00361           GATJobCPIList current = object->cpilist;
00362           GATJobCPIList new_current = new_object->cpilist;
00363           
00364           for (/**/; NULL != current; 
00365                current = current->next, new_current = new_current->next)
00366           {
00367             if (current->cpi == object->cpi)
00368             {
00369               new_object->cpi = new_current->cpi;
00370               break;
00371             }
00372           }
00373           assert(NULL != new_object->cpi);
00374           
00375           /* clone the instance data */
00376           GAT_CREATE_STATUS(GATJobCPI_CloneInstance(object->cpi, &object->data, 
00377             &new_object->data));
00378             
00379           /* clone the monitoring data */
00380           if (NULL != object->data.monitorable)
00381           {
00382             GAT_CREATE_STATUS(GATMonitorable_Impl_Clone(object->data.monitorable, 
00383               &new_object->data.monitorable));
00384           }
00385             
00386           /* register this object with the engine */
00387           GAT_CREATE_STATUS(GATRegistry_AddGATJobToCPIList(
00388             new_object->data.context, new_object->cpi, new_object));
00389         }
00390       } 
00391 
00392       /* destroy the newly allocated object, if some error occured */
00393       if (GAT_FAILED(GAT_CURRENT_STATUS()))
00394       {
00395         GATJob_Destroy(&new_object);
00396       }
00397       else
00398       {
00399         /* return the new object */
00400         *new_handle = new_object;
00401       }
00402     }
00403     
00404     return GAT_RETURN_STATUS();
00405   }
00406   return GAT_INVALID_HANDLE;
00407 }
00408 
00409 /** GATType GATJob_GetType(GATJob_const resource)
00410  *  @brief Return the type of the GATJob
00411  *
00412  *  The function @c GATJob_GetType always returns 
00413  *  @c #GATType_GATJob. 
00414  *
00415  *  @param object The object to inspect
00416  *
00417  *  @return Returns always @c #GATType_GATJob. 
00418  */
00419 GATType
00420 GATJob_GetType(GATJob_const object)
00421 {
00422   GAT_UNUSED_PARAMETER(object);
00423   return GATType_GATJob;
00424 }
00425 
00426 /** GATResult GATJob_GetInterface(GATJob_const file, GATInterface iftype, void const **ifp)
00427  *  @brief Get an interface supported by a GATObject
00428  *
00429  *  The function GATJob_GetInterface allows to get a pointer to an 
00430  *  additional interface supported by this GATJob.
00431  *
00432  *  @param object The object to be asked for the new interface.
00433  *  @param iftype The interface the object is to be asked for.
00434  *  @param ifp The pointer, through which the result is to be returned.
00435  *
00436  *  @return An error type.
00437  */
00438 GATResult 
00439 GATJob_GetInterface(GATJob_const object, GATInterface iftype, 
00440   void const **ifp)
00441 {
00442   if (NULL != object)
00443   {
00444     GAT_STATUS_APIENTRY(object->data.context, "GATJob_GetInterface");
00445     
00446     if (NULL != ifp)
00447     {
00448       if (GATInterface_ISerialisable == iftype || 
00449           GATInterface_IAdvertisable == iftype)
00450       {
00451         *ifp = (void const *) &object->GATSerialisable__vtable;
00452       }
00453       else if (GATInterface_IMonitorable == iftype && NULL != object->data.monitorable)
00454       {
00455         *ifp = (void const *) &object->GATMonitorable__vtable;
00456       }
00457       else
00458       {
00459         *ifp = NULL;
00460         GAT_CREATE_STATUS(GAT_NO_INTERFACE);
00461       }
00462     }
00463     
00464     return GAT_RETURN_STATUS();
00465   }
00466   return GAT_INVALID_HANDLE;
00467 }
00468 
00469 
00470 /* GATMonitorable API */
00471 
00472 /** GATJob_AddMetricListener
00473  *
00474  *  The function GATJob_AddMetricListener adds the passed instance of a 
00475  *  GATMetricListener to the list of GATMetricListeners which are notified of 
00476  *  fired GATMetricEvents of the type described by the provided GATMetric 
00477  *  instance.
00478  *
00479  *  @param object The GATJob instance to add the GATMetricListener to.
00480  *  @param listener The GATMetricListener to call, when the corresponding 
00481  *        GATMetricEvent is fired.
00482  *  @param listener_data The client supplied data, which will be passed through
00483  *        to the GATMetricListener.
00484  *  @param metric The GATMetric instance describing the GATMetricEvent to pass
00485  *        to the GATMetricListener.
00486  *  @param cookie The returned value should be used to remove the 
00487  *        GATMetricListener from this GATMonitorable.
00488  *
00489  *  @return An error code.
00490  */ 
00491 GATResult 
00492 GATJob_AddMetricListener(GATJob object, 
00493   GATMetricListener listener, void *listener_data, GATMetric metric,
00494   GATuint32 *cookie)
00495 {
00496   if (NULL != object)
00497   {
00498     GAT_STATUS_APIENTRY(object->data.context, "GATJob_AddMetricListener");
00499     
00500     if (NULL != object->data.monitorable)
00501     {
00502       GAT_CREATE_STATUS(GATMonitorable_Impl_AddMetricListener(object->data.monitorable, 
00503         listener, listener_data, metric, cookie));
00504     } 
00505     else
00506     { 
00507       /* this may happen, if the adaptor has not registered any GATMetrics */
00508       GAT_CREATE_STATUS(GAT_NO_INTERFACE);
00509     }
00510     
00511     return GAT_RETURN_STATUS();
00512   }
00513   return GAT_INVALID_HANDLE;
00514 }
00515 
00516 /** GATJob_RegisterPolling
00517  *
00518  *  The function GATJob_RegisterPolling registers a continuous 
00519  *  metric with the given GATJob instance.
00520  *
00521  *  @param object The GATJob instance to register the metric with.
00522  *  @param metric The GATMetric instance describing the GATMetricEvent to pass
00523  *        to the GATMetricListener. This metric instance must be of type
00524  *        GATMeasurementType_Continuous, otherwise an error is returned.
00525  *  @param event The pointer to a variable, which should receive the resulting
00526  *        GATMetricEvent. The GATMetricEvent instance should be freed by the 
00527  *        caller when it isn't used anymore.
00528  *  @param cookie The returned value should be used to remove the 
00529  *        GATMetricListener from this GATJob.
00530  *
00531  *  @return An error code.
00532  */ 
00533 GATResult 
00534 GATJob_RegisterPolling(GATJob object, GATMetric metric, 
00535   GATMetricEvent *event, GATuint32 *cookie)
00536 {
00537   if (NULL != object)
00538   {
00539     GAT_STATUS_APIENTRY(object->data.context, "GATJob_RegisterPolling");
00540     
00541     if (NULL != object->data.monitorable)
00542     {
00543       GAT_CREATE_STATUS(GATMonitorable_Impl_RegisterPolling(
00544         object->data.monitorable, metric, 0, cookie));
00545 
00546       /* ask the CPI provider to return the corresponding metric event */
00547       GAT_CREATE_STATUS(GATJobCPI_GetMetricEvent(object->cpi, &object->data, 
00548         metric, event));
00549 
00550       if (GAT_FAILED(GAT_CURRENT_STATUS()) && NULL != cookie && 0 != *cookie)
00551       {
00552         GATMonitorable_Impl_RemoveRegisteredMetric(object->data.monitorable,
00553           metric, *cookie);
00554         *cookie = 0;
00555       }
00556     } 
00557     else
00558     { 
00559       /* this may happen, if the adaptor has not registered any GATMetrics */
00560       GAT_CREATE_STATUS(GAT_NO_INTERFACE);
00561     }
00562     
00563     return GAT_RETURN_STATUS();
00564   }
00565   return GAT_INVALID_HANDLE;
00566 }
00567 
00568 /** GATJob_RemoveRegisteredMetric
00569  *
00570  *  The function GATJob_RemoveRegisteredMetric removes a GATMetricListener, 
00571  *  which was previously registered with GATJob_AddMetricListener.
00572  *
00573  *  @param object The GATJob instance to remove the GATMetricListener from.
00574  *  @param listener The GTAMetricListener to call, when the corresponding 
00575  *        GATMetricEvent is fired.
00576  *  @param metric The GATMetric instance describing the GATMetricEvent to pass
00577  *        to the GATMetricListener.
00578  *  @param cookie This value identifies the GATMetricListener to remove, it 
00579  *        was returned from the corresponding GATMonitorable_AddMetricListener 
00580  *        or GATMonitorable_MetricRegisterPolling functions.
00581  *  
00582  *  @return An error code.
00583  */
00584 GATResult 
00585 GATJob_RemoveRegisteredMetric(GATJob object, 
00586   GATMetric metric, GATuint32 cookie)
00587 {
00588   if (NULL != object)
00589   {
00590     GAT_STATUS_APIENTRY(object->data.context, "GATJob_RemoveRegisteredMetric");
00591     
00592     if (NULL != object->data.monitorable)
00593     {
00594       GAT_CREATE_STATUS(GATMonitorable_Impl_RemoveRegisteredMetric(
00595         object->data.monitorable, metric, cookie));
00596     } 
00597     else
00598     { 
00599       /* this may happen, if the adaptor has not registered any GATMetrics */
00600       GAT_CREATE_STATUS(GAT_NO_INTERFACE);
00601     }
00602     
00603     return GAT_RETURN_STATUS();
00604   }
00605   return GAT_INVALID_HANDLE;
00606 }
00607 
00608 /** GATJob_GetMetrics
00609  *
00610  *  The function GATJob_GetMetrics returns a list of metrics supported 
00611  *  by this GATJob.
00612  *
00613  *  @param object The GATJob instance, for which the supported metrics 
00614  *        should be returned.
00615  *  @param metrics The pointer to the variable, which receives the resulting 
00616  *        list of metrics.
00617  *
00618  *  @return An error code.
00619  */
00620 GATResult 
00621 GATJob_GetMetrics(GATJob_const object, GATList_GATMetric *metrics)
00622 {
00623   if (NULL != object)
00624   {
00625     GAT_STATUS_APIENTRY(object->data.context, "GATJob_GetMetrics");
00626     
00627     if (NULL != object->data.monitorable)
00628     {
00629       GAT_CREATE_STATUS(GATMonitorable_Impl_GetMetrics(object->data.monitorable, 
00630         metrics));
00631     } 
00632     else
00633     { 
00634       /* this may happen, if the adaptor has not registered any GATMetrics */
00635       GAT_CREATE_STATUS(GAT_NO_INTERFACE);
00636     }
00637     
00638     return GAT_RETURN_STATUS();
00639   }
00640   return GAT_INVALID_HANDLE;
00641 }
00642 
00643 
00644 /* GATAdvertiseable API */
00645 
00646 /** GATJobCPI_SerialiseCallback
00647  *
00648  *  The function GATJobCPI_SerialiseCallback is used as a callback function 
00649  *  for the serialisation of a GATJob object. 
00650  *  It should be provided to 
00651  *  serialise the associated CPI provider data for the given object.
00652  *
00653  *  @param object The object to serialise. This is the same as the object 
00654  *        passed as the first parameter to the function GATXds_SerialiseObject.
00655  *  @param stream The stream interface to use for the serialisation.
00656  *  @param clear_dirty If the clear_dirty parameter is set to GATTrue, the 
00657  *        internal dirty flag of this object is to be reset (no used here)
00658  *
00659  *  @return An error code.
00660  *
00661  *  @remark This function is called from the GAT engine, there is no need to 
00662  *        call it directly.
00663  */
00664 static GATResult 
00665 GATJobCPI_SerialiseCallback(GATObject handle, GATObject stream, 
00666   GATBool clear_dirty)
00667 {
00668   GATJob object = GATObject_ToGATJob(handle);
00669   if (NULL != object)
00670   {
00671     GAT_USES_STATUS(object->data.context, "GATJobCPI_SerialiseCallback");
00672     
00673     GAT_CREATE_STATUS(GATJobCPI_Serialise(object->cpi, &object->data, stream, 
00674       clear_dirty));
00675 
00676     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()) && GATTrue == clear_dirty)
00677     {
00678       object->data.isdirty = GATFalse;
00679     }
00680 
00681     return GAT_RETURN_STATUS();
00682   }
00683   return GAT_INVALID_HANDLE;
00684 }
00685 
00686 /** GATResult GATJob_Serialise(GATJob object, GATObject stream, GATBool clear_dirty)
00687  *  @brief Serialise a GATJob object
00688  *
00689  *  The function GATJob_Serialise serialises the given GATJob object into the
00690  *  given stream. 
00691  *
00692  *  @param object The GATJob object to serialise.
00693  *  @param stream The stream interface to use for the serialisation.
00694  *  @param clear_dirty If the clear_dirty parameter is set to GATTrue, the 
00695  *        internal dirty flag of this object is to be reset (no used here)
00696  *
00697  *  @return An error code.
00698  */
00699 GATResult 
00700 GATJob_Serialise(GATJob object, GATObject stream, GATBool clear_dirty)
00701 {
00702   if (NULL != object)
00703   {
00704     GAT_USES_STATUS(object->data.context, "GATJob_Serialise");
00705     
00706     GAT_CREATE_STATUS(GATXds_SerialiseObject(GATJob_ToGATObject(object), stream, 
00707       clear_dirty, GATJobCPI_SerialiseCallback, "uint32 uint32 string",
00708       GATJOB_VERSION1, (GATuint32) object->data.state, object->data.jobid));
00709 
00710     return GAT_RETURN_STATUS();
00711   }
00712   return GAT_INVALID_HANDLE;
00713 }
00714 
00715 /** GATJob_VersionCallback
00716  *
00717  *  The function GATJob_VersionCallback is used as a callback function
00718  *  during the de-serialisation of a GATJob. It should be provided to test,
00719  *  whether the de-serialised version matches the expected version.
00720  *
00721  *  @param version The version number, which was de-serialised from the stream.
00722  *
00723  *  @return This function should return GATTrue, if the version matches the 
00724  *        expected value (version is valid), GATFalse otherwise.
00725  *
00726  *  @remark This function is called from the GAT engine, there is no need to 
00727  *        call it directly.
00728  */
00729 static GATBool
00730 GATJob_VersionCallback(GATuint32 version)
00731 {
00732   GATBool retval = GATFalse;
00733   if ((version & ~GATJOB_MINOR_MASK) <= GATJOB_LASTVERSION)
00734   {
00735     retval = GATTrue;
00736   }
00737   return retval;
00738 }
00739 
00740 /** GATJob_DeSerialiseCallback
00741  *
00742  *  The function GATJob_DeSerialiseCallback is used as a callback function
00743  *  during the de-serialisation of a GATJob. It should be provided for the
00744  *  instantiation of the new GATJob object based on the already de-serialised 
00745  *  data items and the de-serialisation of the associated CPI provider data for 
00746  *  the given object.
00747  *
00748  *  @param context The GAT context to be used for object construction.
00749  *  @param stream The stream interface to use for the serialisation.
00750  *  @param object The pointer to the variable, which should receive the newly 
00751  *        constructed object.
00752  *  @param version The version of the saved data read from the input stream.
00753  *  @param args This parameter is the pointer to the va_list containing 
00754  *        pointers to the already de-serialised data items accordingly to the
00755  *        format string, provided during the call to the 
00756  *        GATJob_DeSerialise function.
00757  *
00758  *  @return An error code.
00759  *
00760  *  @remark This function is called from the GAT engine, there is no need to 
00761  *        call it directly.
00762  */
00763 static GATResult 
00764 GATJob_DeSerialiseCallback(GATContext context, GATObject stream, 
00765   GATObject *new_object, GATuint32 version, va_list args)
00766 {
00767   GAT_USES_STATUS(context, "GATJob_DeSerialiseCallback");
00768   
00769   /* the version was eaten already */
00770   GATuint32 *state = va_arg(args, GATuint32 *);
00771   GATJobID *jobid = va_arg(args, GATJobID *);
00772   GATJob object = NULL;
00773   
00774   /* construct the new object */
00775   GAT_CREATE_STATUS(GATJob_DeSerialise_Create(context, stream, *jobid, 
00776     (GATJobState)*state, &object));
00777 
00778   GAT_UNUSED_PARAMETER(version);
00779   if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00780   {
00781     if (NULL != object)
00782     {
00783       *new_object = GATJob_ToGATObject(object);
00784     }
00785     else
00786     {
00787       GATJob_Destroy(&object);
00788       GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
00789     }
00790   }
00791   
00792   return GAT_RETURN_STATUS();
00793 }
00794 
00795 /** GATJob GATJob_DeSerialise(GATContext context, GATObject stream, GATBool clear_dirty)
00796  *  @brief De-serialise a GATJob object
00797  *
00798  *  The function GATJob_DeSerialise de-serialises a streamed GATJob object  
00799  *  from the given stream  It constructs a new instance of the de-serialised 
00800  *  object.
00801  *
00802  *  @param context The GAT context to be used for object construction.
00803  *  @param stream The stream interface to use for the serialisation.
00804  *  @param result The pointer to a variable, which receives the status code of
00805  *        the operation.
00806  *
00807  *  @return The newly constructed GATJob object.
00808  */
00809 GATJob 
00810 GATJob_DeSerialise(GATContext context, GATObject stream, GATResult *result)
00811 {
00812   GAT_USES_STATUS(context, "GATJob_DeSerialise");
00813   
00814   GATObject object = NULL;     /* the new object will be created here */
00815   GATJob job = NULL;
00816   
00817   /* we must provide all instance data items to be de-serialised for this
00818      GATJob object accordingly to the provided format string */
00819   GATuint32 version = 0;
00820   GATJobID jobid = NULL;
00821   GATuint32 state = GATJobState_Unknown;
00822   
00823   /* read the data */
00824   GAT_CREATE_STATUS(GATXds_DeSerialiseObject(context, stream, 
00825     GATJob_DeSerialiseCallback, GATJob_VersionCallback, &object, 
00826     "uint32 uint32 string", &version, &state, &jobid));
00827 
00828   GATString_Destroy(&jobid);
00829   
00830   job = GATObject_ToGATJob(object);
00831   if (NULL == job)
00832   {
00833     GAT_CREATE_STATUS(GAT_BAD_OBJECT_CONVERSION);
00834   }
00835   
00836   if (GAT_FAILED(GAT_CURRENT_STATUS()))
00837   {
00838     GATObject_Destroy(&object);
00839     job = NULL;
00840   }
00841   
00842   if (NULL != result)
00843   { 
00844     *result = GAT_CURRENT_STATUS();
00845   }
00846   
00847   GAT_STORE_STATUS();
00848   return job;
00849 }
00850 
00851 /** GATJob_GetIsDirty
00852  *  
00853  *  The function GATJob_GetIsDirty retrieves the status of the dirty flag of 
00854  *  this GATJob object.
00855  *
00856  *  @param file The GATJob object to inspect for its dirty status.
00857  *  @param isdirty The pointer to a variable, which receives the dirty status.
00858  *
00859  *  @return An error code.
00860  */
00861 GATResult GATJob_GetIsDirty(GATJob_const object, GATBool *isdirty)
00862 {
00863   if (NULL != object)
00864   {
00865     GAT_STATUS_APIENTRY(object->data.context, "GATJob_GetIsDirty");
00866     
00867     if (NULL != isdirty)
00868     {
00869       *isdirty = object->data.isdirty;
00870     }
00871     else
00872     {
00873       GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
00874     }
00875     
00876     return GAT_RETURN_STATUS();
00877   }  
00878   return GAT_INVALID_PARAMETER;
00879 }
00880 
00881 
00882 /* Local functions */
00883 
00884 /** GATJob_DeSerialise_Create
00885  *
00886  *  The function GATJob_DeSerialise_Create creates a new GATJob object.
00887  *  Further it tries find a CPI provider to associate with this file object. 
00888  *  The CPI provider is selected by testing, which adapter is able to handle the 
00889  *  streamed instance data of the original CPI provider.
00890  *
00891  *  @param context The GAT context to use for creation of the GATJob object.
00892  *  @param stream The object from which the adaptor should read the streamed
00893  *        instance data.
00894  *  @param state The state of the GATJob object.
00895  *  @param jobid The job id of the job to create.
00896  *  @param new_object The pointer to the variable, which should receive the 
00897  *        newly constructed GATJob object.
00898  *
00899  *  @return An error code.
00900  */
00901 static GATResult 
00902 GATJob_DeSerialise_Create(GATContext context, GATObject stream, GATJobID jobid,
00903   GATJobState state, GATJob *object)
00904 {
00905   GAT_USES_STATUS(context, "GATJob_DeSerialise_Create");
00906   
00907   GATJob new_object = (GATJob) malloc(sizeof(struct GATJob_S));
00908 
00909   if(NULL != new_object)
00910   {
00911     memset(new_object, 0, sizeof(struct GATJob_S));
00912     new_object->GATObject__vtable = &GATJob__vtable;
00913     new_object->GATSerialisable__vtable = &GATJob_ISerialisable__vtable;
00914     new_object->GATMonitorable__vtable = &GATJob_IMonitorable__vtable;
00915     
00916     new_object->data.context = context;
00917     new_object->data.isdirty = GATFalse;
00918     new_object->data.source = GATJob_ToGATObject_const(new_object);
00919     new_object->data.state = state;
00920     
00921     GAT_CREATE_STATUS(GATString_Clone(jobid, &new_object->data.jobid));
00922     
00923     /* find a CPI object, which can handle the data at the given stream 
00924        location */
00925     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00926     {
00927       GATRegistry_const registry = GATContext_internal_GetRegistry(context);
00928       GATPreferences_const preferences = NULL;
00929             
00930       /* use default preferences, if appropriate */
00931       if (NULL == preferences)
00932       {
00933         preferences = GATContext_GetPreferences(context);
00934       }
00935 
00936       new_object->cpilist = GATRegistry_FindGATJobCPI(registry, preferences);
00937       if (NULL == new_object->cpilist)
00938       {
00939         GAT_CREATE_STATUS(GAT_NO_REGISTERED_CPI);
00940       }
00941       else 
00942       {
00943         /* find out the current stream position */
00944         GATuint32 offset = 0;
00945         GATBool found_cpi = GATFalse;
00946         GATJobCPIList current = NULL;
00947         
00948         GAT_CREATE_STATUS(GATStreamable_Seek(stream, GATOrigin_Current, 0, 
00949           &offset));
00950         if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00951         {
00952           /* create new instance data of the CPI provider */
00953           for(current = new_object->cpilist; NULL != current; current = current->next)
00954           {
00955             /* try, whether this CPI can handle the input */
00956             GAT_CREATE_STATUS(GATJobCPI_DeSerialise(current->cpi, stream, 
00957               &new_object->data));
00958             if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00959             {
00960               new_object->cpi = current->cpi;
00961               found_cpi = GATTrue;
00962               break;
00963             }
00964             
00965             /* reset stream pointer to the beginning of the CPI instance data */
00966             GAT_CREATE_STATUS(GATStreamable_Seek(stream, GATOrigin_Set, offset, 0));
00967           }
00968         }
00969         
00970         /* no available CPI object can handle this */
00971         if (GATFalse == found_cpi)
00972         {
00973           GAT_CREATE_STATUS(GAT_NO_MATCHING_CPI);
00974         }
00975         else
00976         {
00977           /* try to re-init the monitoring support, since the adaptor found may
00978              support another set of GATMetric's, than the original one. */
00979           GATList_GATMetric metrics = NULL;
00980 
00981           GATResult retval = GATJobCPI_GetMetrics(new_object->cpi, &new_object->data, 
00982             &metrics);            
00983           if (GAT_SUCCEEDED(retval))
00984           {
00985             new_object->data.monitorable = GATMonitorable_Impl_Create(metrics);
00986             if (NULL != new_object->data.monitorable)
00987             {
00988               GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00989             }
00990             GATList_GATMetric_Destroy(&metrics);
00991           }
00992           else if (GAT_NOTIMPL != retval)
00993           {
00994             GAT_CREATE_STATUS(retval);
00995           }
00996           else
00997           {
00998             retval = GAT_SUCCESS;   /* no monitoring supported here */
00999           }
01000 
01001           if (GAT_SUCCEEDED(retval))
01002           {
01003             GAT_CREATE_STATUS(GATRegistry_AddGATJobToCPIList(new_object->data.context, 
01004               new_object->cpi, new_object));
01005           }
01006         }
01007       }
01008     }
01009   }
01010   else
01011   {
01012     GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
01013   }
01014   
01015   if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
01016   {
01017     if (NULL != new_object)
01018     {
01019       *object = new_object;
01020     }
01021     else
01022     {
01023       GATJob_Destroy(&new_object);
01024       GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
01025     }
01026   }
01027   else
01028   {
01029     GATJob_Destroy(&new_object);
01030   }
01031   
01032   return GAT_RETURN_STATUS();
01033 }
01034 
01035 /** GATJob_UnSchedule
01036  *
01037  *  The function GATJob_UnSchedule guarantees that this GATJob is not scheduled 
01038  *  to a job queue, its state is GAT Initial. This operation can only be called 
01039  *  on a GATJob in the GAT Scheduled state, otherwise an error will is issued.
01040  *
01041  *  @param object The job to unschedule.
01042  *
01043  *  @return An error code.
01044  */
01045 GATResult GATJob_UnSchedule(GATJob_const object)
01046 {
01047   if (NULL != object)
01048   {
01049     GAT_STATUS_APIENTRY(object->data.context, "GATJob_UnSchedule");
01050     GAT_CREATE_STATUS(GATJobCPI_UnSchedule(object->cpi, &object->data));
01051     return GAT_RETURN_STATUS();
01052   }
01053   return GAT_INVALID_HANDLE;
01054 }
01055 
01056 /** GATJob_Checkpoint
01057  *
01058  *  The function GATJob_Checkpoint triggers a checkpoint operation for the 
01059  *  GATJob. The call can only succeed on processes which support application 
01060  *  level checkpointing, or on resources which provide system level 
01061  *  checkpointing.
01062  *  The call returns immediately after delivering the checkpointing request to 
01063  *  the job or to the resource the job is running on; the actual checkpoint 
01064  *  may happen some time after this return.
01065  *
01066  *  @param object The job to checkpoint.
01067  *
01068  *  @return An error code.
01069  */
01070 GATResult GATJob_Checkpoint(GATJob_const object)
01071 {
01072   if (NULL != object)
01073   {
01074     GAT_STATUS_APIENTRY(object->data.context, "GATJob_Checkpoint");
01075     GAT_CREATE_STATUS(GATJobCPI_Checkpoint(object->cpi, &object->data));
01076     return GAT_RETURN_STATUS();
01077   }
01078   return GAT_INVALID_HANDLE;
01079 }
01080 
01081 /** GATJob_CloneJob
01082  *
01083  *  The function GATJob_CloneJob creates a copy of the GATJob. The resulting 
01084  *  GATJob has the same GATSoftwareDescription in its GATJobDescription, but 
01085  *  the GATResourceDescriptions or GATResources of its GATJobDescription may be 
01086  *  altered.
01087  *
01088  *  @param object The job to clone to a new hardware.
01089  *  @param hr (optional) The GATHardwareResource to use to schedule the clones 
01090  *        job. If this parameter is not given (zero) the GATHardwareResource is 
01091  *        used, which was used to create the current GATJob.
01092  *  @param cloned_job The pointer to a variable receiving the cloned job object.
01093  *
01094  *  @return An error code.
01095  */
01096 GATResult GATJob_CloneJob(GATJob_const object, GATHardwareResource_const hr,
01097   GATJob *cloned_job)
01098 {
01099   if (NULL != object)
01100   {
01101     GAT_STATUS_APIENTRY(object->data.context, "GATJob_CloneJob");
01102     GAT_CREATE_STATUS(GATJobCPI_CloneJob(object->cpi, &object->data, hr, 
01103       cloned_job));
01104     return GAT_RETURN_STATUS();
01105   }
01106   return GAT_INVALID_HANDLE;
01107 }
01108 
01109 /** GATJob_Migrate
01110  *
01111  *  The function GATJob_Migrate provides similar functionality to the 
01112  *  #GATJob_CloneJob operation. The only difference is that the calling GATJob 
01113  *  instance is discontinued after the new job is spawned off successfully — 
01114  *  its state is #GATJobState_Stopped then.
01115  *
01116  *  @param object The job to migrate to a new hardware.
01117  *  @param hr (optional) The GATHardwareResource to use to schedule the clones 
01118  *        job. If this parameter is not given (zero) the GATHardwareResource is 
01119  *        used, which was used to create the current GATJob.
01120  *  @param migrated_job The pointer to a variable receiving the cloned job 
01121  *        object.
01122  *
01123  *  @return An error code.
01124  */
01125 GATResult GATJob_Migrate(GATJob_const object, GATHardwareResource_const hr,
01126   GATJob *migrated_job)
01127 {
01128   if (NULL != object)
01129   {
01130     GAT_STATUS_APIENTRY(object->data.context, "GATJob_Migrate");
01131     GAT_CREATE_STATUS(GATJobCPI_Migrate(object->cpi, &object->data, hr, 
01132       migrated_job));
01133     return GAT_RETURN_STATUS();
01134   }
01135   return GAT_INVALID_HANDLE;
01136 }
01137 
01138 /** GATJob_Stop
01139  *
01140  *  The function GATJob_Stop stops the GATJob. Upon a successful call to this 
01141  *  operation, the processes associated with the GATJob are forcibly 
01142  *  terminated. This operation can only be called on a GATJob in the 
01143  *  #GATJobState_Running state.
01144  *
01145  *  @param object The job to stop.
01146  *
01147  *  @return An error code.
01148  */
01149 GATResult GATJob_Stop(GATJob object)
01150 {
01151   if (NULL != object)
01152   {
01153     GAT_STATUS_APIENTRY(object->data.context, "GATJob_Stop");
01154     GAT_CREATE_STATUS(GATJobCPI_Stop(object->cpi, &object->data));
01155     return GAT_RETURN_STATUS();
01156   }
01157   return GAT_INVALID_HANDLE;
01158 }
01159 
01160 /** GATJob_GetJobDescription
01161  *
01162  *  The function GATJob_GetJobDescription returns the GATJobDescription 
01163  *  instance used to create that GATJob instance.
01164  *
01165  *  @param object The job for which the associated GATJobDescription should be
01166  *        returned.
01167  *  @param jd The ppointer to a variable, which should receive the associated 
01168  *        job description.
01169  *
01170  *  @return An error code.
01171  */
01172 GATResult GATJob_GetJobDescription(GATJob_const object, 
01173   GATJobDescription_const *jd)
01174 {
01175   if (NULL != object)
01176   {
01177     GAT_STATUS_APIENTRY(object->data.context, "GATJob_GetJobDescription");
01178     GAT_CREATE_STATUS(GATJobCPI_GetJobDescription(object->cpi, &object->data, 
01179       jd));
01180     return GAT_RETURN_STATUS();
01181   }
01182   return GAT_INVALID_HANDLE;
01183 }
01184 
01185 /** GATJob_GetState
01186  *
01187  *  The function GATJob_GetState returns the state of the represented process. 
01188  *  This is one of the associated public class constants #GATJobState_Initial, 
01189  *  #GATJobState_Scheduled, #GATJobState_Running, or #GATJobState_Stopped.
01190  *
01191  *  @param object The job The job for which the associated GATJobState should be
01192  *        returned.
01193  *  @param state The pointer to a variable, which should receive the resulting
01194  *        GATJobState.
01195  *
01196  *  @return An error code.
01197  */
01198 GATResult GATJob_GetState(GATJob_const object, GATJobState *state)
01199 {
01200   if (NULL != object)
01201   {
01202     GAT_STATUS_APIENTRY(object->data.context, "GATJob_GetState");
01203     
01204     if (NULL != state)
01205     {
01206       *state = object->data.state;
01207     }
01208     else
01209     {
01210       GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
01211     }
01212     
01213     return GAT_RETURN_STATUS();
01214   }
01215   return GAT_INVALID_HANDLE;
01216 }
01217 
01218 /** GATJob_GetInfo
01219  *
01220  *  The function GATJob_GetInfo returns an instance of the class GATTable, 
01221  *  which contains the essential information about the GATJob object, such as
01222  *  the host name, the schedule time, the start time, the stop time, whether 
01223  *  GATJob is checkpointable etc.
01224  *
01225  *  @param object The job to ask for its parameter info.
01226  *  @param jobinfo The pointer to a variable, which should receive the returned
01227  *        GATTable containing the job information.
01228  *
01229  *  @return An error code.
01230  */
01231 GATResult GATJob_GetInfo(GATJob_const object, GATTable_const *jobinfo)
01232 {
01233   if (NULL != object)
01234   {
01235     GAT_STATUS_APIENTRY(object->data.context, "GATJob_GetInfo");
01236     GAT_CREATE_STATUS(GATJobCPI_GetInfo(object->cpi, &object->data, jobinfo));
01237     return GAT_RETURN_STATUS();
01238   }
01239   return GAT_INVALID_HANDLE;
01240 }
01241 
01242 /** GATJob_GetJobID
01243  *
01244  *  The function GATJob_GetJobID returns the job id, a globally unique 
01245  *  identifier for the represented process corresponding to this instance. This 
01246  *  operation SHOULD be called on a GATJob instance only when the instance is 
01247  *  in a GAT Running or GAT Scheduled state, otherwise an error will be issued.
01248  *
01249  *  @param object The job to get the job id for.
01250  *  @param jobid The pointer to a variable, which should receive the resulting 
01251  *        job id.
01252  *
01253  *  @return An error code.
01254  */
01255 GATResult 
01256 GATJob_GetJobID(GATJob_const object, GATJobID_const *jobid)
01257 {
01258   if (NULL != object)
01259   {
01260     GAT_STATUS_APIENTRY(object->data.context, "GATJob_GetJobID");
01261     
01262     if (NULL != jobid)
01263     {
01264       *jobid = object->gatjobid;
01265     }
01266     else
01267     {
01268       GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
01269     }
01270     
01271     return GAT_RETURN_STATUS();
01272   }
01273   return GAT_INVALID_HANDLE;
01274 }
01275 
01276 /** GATJob_GetNativeID
01277  *
01278  *  The function GATJob_GetNativeID returns the job id, which was assigned to 
01279  *  this job by the resource management service starting this job. If no such
01280  *  native id exists, this function will fail.
01281  *
01282  *  @param object The job to get the job id for.
01283  *  @param jobid The pointer to a variable, which should receive the resulting 
01284  *        GRMS job id.
01285  *
01286  *  @return An error code.
01287  */
01288 GATResult 
01289 GATJob_GetNativeID(GATJob_const object, GATJobID_const *jobid)
01290 {
01291   if (NULL != object)
01292   {
01293     GAT_STATUS_APIENTRY(object->data.context, "GATJob_GetNativeID");
01294     
01295     if (NULL != jobid)
01296     {
01297       *jobid = object->data.jobid;
01298     }
01299     else
01300     {
01301       GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
01302     }
01303     
01304     return GAT_RETURN_STATUS();
01305   }
01306   return GAT_INVALID_HANDLE;
01307 }
01308 
01309 /** GATJob_GetStatus
01310  *
01311  *  The function GATJob_GetStatus SHOULD provide a GATStatus instance which 
01312  *  gives further information as to the cause of the error, if the job is in 
01313  *  the GAT SubmissionError state.
01314  *
01315  *  @param object The job to ask for the associated GATStatus object.
01316  *  @param status The variable, which should receive the associated GATStatus
01317  *        object.
01318  *
01319  *  @return An error code.
01320  */
01321 GATResult GATJob_GetStatus(GATJob_const object, GATStatus_const *jobstatus)
01322 {
01323   if (NULL != object)
01324   {
01325     GAT_STATUS_APIENTRY(object->data.context, "GATJob_GetStatus");
01326     GAT_CREATE_STATUS(GATJobCPI_GetStatus(object->cpi, &object->data, 
01327       jobstatus));
01328     return GAT_RETURN_STATUS();
01329   }
01330   return GAT_INVALID_HANDLE;
01331 }
01332 
01333 /*  GATJob_GetCPIInstanceData
01334  *  
01335  *  The function GATJob_GetCPIInstanceData returns the CPI instance data, 
01336  *  associated with the given GATJob object.
01337  *
01338  *  @param job The object, for which to return the CPI instance data.
01339  *  @param data The pointer to the variable, which should receive the
01340  *        resulting CPI instance data.
01341  *
01342  *  @return An error code.
01343  */
01344 static GATResult
01345 GATJob_GetCPIInstanceData(GATJob job, void **data)
01346 {
01347   if (NULL != job)
01348   {
01349     GAT_USES_STATUS(job->data.context, "GATJob_GetCPIInstanceData");
01350     
01351     if (NULL != data)
01352     {
01353       *data = (void *)&job->data;
01354     }
01355     else
01356     {
01357       GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
01358     }
01359     
01360     return GAT_RETURN_STATUS();
01361   }
01362   return GAT_INVALID_HANDLE;
01363 }
01364 
01365 /*  GATJob_internal_SetGATJobId
01366  *  
01367  *  The function GATJob_internal_SetGATJobId sets the GAT related job id, which
01368  *  is maintained independently of the job id assigned my some resource 
01369  *  management system.
01370  *
01371  */
01372 GATResult 
01373 GATJob_internal_SetGATJobId(GATJob job, GATString_const gatjobid)
01374 {
01375   if (NULL != job)
01376   {
01377     GAT_USES_STATUS(job->data.context, "GATJob_internal_SetGATJobId");
01378     
01379     if (NULL != job->gatjobid)
01380     {
01381       GATString_Destroy(&job->gatjobid);
01382     }
01383     GAT_CREATE_STATUS(GATString_Clone(gatjobid, &job->gatjobid));
01384     
01385     return GAT_RETURN_STATUS();
01386   }
01387   return GAT_INVALID_HANDLE;
01388 }