extensions/net.sf.basedb.opengrid/trunk/src/net/sf/basedb/opengrid/config/ClusterConfig.java

Code
Comments
Other
Rev Date Author Line
4254 25 Nov 16 nicklas 1 package net.sf.basedb.opengrid.config;
4126 26 Sep 16 nicklas 2
4212 08 Nov 16 nicklas 3 import java.text.SimpleDateFormat;
4275 19 Dec 16 nicklas 4 import java.util.ArrayList;
4275 19 Dec 16 nicklas 5 import java.util.Collections;
6827 31 Aug 22 nicklas 6 import java.util.HashMap;
4275 19 Dec 16 nicklas 7 import java.util.List;
4212 08 Nov 16 nicklas 8 import java.util.Locale;
6827 31 Aug 22 nicklas 9 import java.util.Map;
4212 08 Nov 16 nicklas 10
4275 19 Dec 16 nicklas 11 import org.json.simple.JSONArray;
4257 30 Nov 16 nicklas 12 import org.json.simple.JSONObject;
4257 30 Nov 16 nicklas 13
4317 23 Jan 17 nicklas 14 import net.sf.basedb.core.DbControl;
4317 23 Jan 17 nicklas 15 import net.sf.basedb.core.JobAgent;
4254 25 Nov 16 nicklas 16 import net.sf.basedb.opengrid.OpenGridCluster;
5981 07 Jul 20 nicklas 17 import net.sf.basedb.opengrid.engine.ClusterEngine;
4275 19 Dec 16 nicklas 18 import net.sf.basedb.opengrid.json.JSONOption;
4257 30 Nov 16 nicklas 19 import net.sf.basedb.opengrid.json.JSONOptions;
4212 08 Nov 16 nicklas 20 import net.sf.basedb.util.formatter.DateFormatter;
4212 08 Nov 16 nicklas 21
4126 26 Sep 16 nicklas 22 /**
5981 07 Jul 20 nicklas 23   Configuration settings related to the cluster.
4126 26 Sep 16 nicklas 24   The information becomes readonly when a {@link OpenGridCluster} 
4126 26 Sep 16 nicklas 25   instance has been created.
4126 26 Sep 16 nicklas 26   
4126 26 Sep 16 nicklas 27   @author nicklas
4126 26 Sep 16 nicklas 28   @since 1.0
4126 26 Sep 16 nicklas 29 */
4126 26 Sep 16 nicklas 30 public class ClusterConfig 
4126 26 Sep 16 nicklas 31   extends AbstractLockable<ClusterConfig>
4126 26 Sep 16 nicklas 32 {
4212 08 Nov 16 nicklas 33   /**
4212 08 Nov 16 nicklas 34     Convert date string from the date command into Date objects.
4212 08 Nov 16 nicklas 35     Example: 2014-03-21 08:59:09
4212 08 Nov 16 nicklas 36   */
4212 08 Nov 16 nicklas 37   public static final DateFormatter DATE_CMD = 
4212 08 Nov 16 nicklas 38     new DateFormatter(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH));
4212 08 Nov 16 nicklas 39
5981 07 Jul 20 nicklas 40   private final ClusterType type;
4126 26 Sep 16 nicklas 41   private String jobFolder;
4264 14 Dec 16 nicklas 42   private String tmpFolder;
4264 14 Dec 16 nicklas 43   private String tmpFolderDebug;
4212 08 Nov 16 nicklas 44   private String dateCommand;
4257 30 Nov 16 nicklas 45   private String hostInfoCommand;
4257 30 Nov 16 nicklas 46   private String ogsInfoCommand;
4255 28 Nov 16 nicklas 47   private String jobAgentExternalId;
6827 31 Aug 22 nicklas 48   private final List<NodeConfig> nodes;
6827 31 Aug 22 nicklas 49   private final Map<String, String> customOptions;
4126 26 Sep 16 nicklas 50   
5981 07 Jul 20 nicklas 51   /**
5981 07 Jul 20 nicklas 52     Create a new Open Grid cluster configuration.
5981 07 Jul 20 nicklas 53     @deprecated In 1.4, use {@link ClusterConfig(ClusterType)} instead
5981 07 Jul 20 nicklas 54   */
5981 07 Jul 20 nicklas 55   @Deprecated
4126 26 Sep 16 nicklas 56   public ClusterConfig()
4212 08 Nov 16 nicklas 57   {
5981 07 Jul 20 nicklas 58     this(ClusterType.OPENGRID);
5981 07 Jul 20 nicklas 59   }
5981 07 Jul 20 nicklas 60
5981 07 Jul 20 nicklas 61   /**
5981 07 Jul 20 nicklas 62     Create new cluster configuration for the given cluster
5981 07 Jul 20 nicklas 63     type. The configuration is initialized with 
5981 07 Jul 20 nicklas 64     {@link ClusterEngine#setDefaultConfig(ClusterConfig)}
5981 07 Jul 20 nicklas 65     @param type
5981 07 Jul 20 nicklas 66   */
5981 07 Jul 20 nicklas 67   public ClusterConfig(ClusterType type)
5981 07 Jul 20 nicklas 68   {
5981 07 Jul 20 nicklas 69     this.type = type;
4212 08 Nov 16 nicklas 70     dateCommand = "date +'%Y-%m-%d %T'";
4257 30 Nov 16 nicklas 71     hostInfoCommand = "uname -srmo";
5981 07 Jul 20 nicklas 72     tmpFolder = "/tmp";
4275 19 Dec 16 nicklas 73     nodes = new ArrayList<>();
6827 31 Aug 22 nicklas 74     customOptions = new HashMap<>();
5984 10 Jul 20 nicklas 75     type.createEngine().setDefaultConfig(this);
4212 08 Nov 16 nicklas 76   }
5981 07 Jul 20 nicklas 77   
5981 07 Jul 20 nicklas 78   public ClusterType getType()
5981 07 Jul 20 nicklas 79   {
5981 07 Jul 20 nicklas 80     return type;
5981 07 Jul 20 nicklas 81   }
5981 07 Jul 20 nicklas 82   
4126 26 Sep 16 nicklas 83   /**
4126 26 Sep 16 nicklas 84     Get the path to the primary job folder on the 
4126 26 Sep 16 nicklas 85     Open Grid cluster.
4126 26 Sep 16 nicklas 86   */
4126 26 Sep 16 nicklas 87   public String getJobFolder()
4126 26 Sep 16 nicklas 88   {
4126 26 Sep 16 nicklas 89     return jobFolder;
4126 26 Sep 16 nicklas 90   }
4126 26 Sep 16 nicklas 91   
4126 26 Sep 16 nicklas 92   /**
5981 07 Jul 20 nicklas 93     Set the path to the primary job folder on the cluster.
4126 26 Sep 16 nicklas 94     
4126 26 Sep 16 nicklas 95     @throws IllegalStateException If this instance has been locked
4126 26 Sep 16 nicklas 96   */
4126 26 Sep 16 nicklas 97   public void setJobFolder(String jobFolder)
4126 26 Sep 16 nicklas 98   {
4126 26 Sep 16 nicklas 99     checkLocked("setJobFolder()");
4126 26 Sep 16 nicklas 100     this.jobFolder = jobFolder;
4126 26 Sep 16 nicklas 101   }
4212 08 Nov 16 nicklas 102   
4212 08 Nov 16 nicklas 103   /**
4264 14 Dec 16 nicklas 104     Get the path to a temporary folder that a job can use
4264 14 Dec 16 nicklas 105     for storing temporary data. Typically, the data in
4264 14 Dec 16 nicklas 106     this folder will be deleted after the job has been
4264 14 Dec 16 nicklas 107     completed. The help with debugging  a second temporary
4264 14 Dec 16 nicklas 108     folder can be set to a location that is not deleted afterwards.
4264 14 Dec 16 nicklas 109     If no debug temporary folder has been specified the regular 
4264 14 Dec 16 nicklas 110     temporary folder is returned.
4264 14 Dec 16 nicklas 111   */
4264 14 Dec 16 nicklas 112   public String getTmpFolder(boolean debug)
4264 14 Dec 16 nicklas 113   {
4264 14 Dec 16 nicklas 114     return debug && tmpFolderDebug != null ? tmpFolderDebug : tmpFolder;
4264 14 Dec 16 nicklas 115   }
4264 14 Dec 16 nicklas 116   
4264 14 Dec 16 nicklas 117   /**
4264 14 Dec 16 nicklas 118     Set the path to the temporary job folder on the
5981 07 Jul 20 nicklas 119     cluster. It is possible to set one regular temporary 
5981 07 Jul 20 nicklas 120     folder and one debug temporary folder.
4264 14 Dec 16 nicklas 121     
4264 14 Dec 16 nicklas 122     @throws IllegalStateException If this instance has been locked
4264 14 Dec 16 nicklas 123   */
4264 14 Dec 16 nicklas 124   public void setTmpFolder(String tmpFolder, boolean debug)
4264 14 Dec 16 nicklas 125   {
4264 14 Dec 16 nicklas 126     checkLocked("setTmpFolder()");
4264 14 Dec 16 nicklas 127     if (debug)
4264 14 Dec 16 nicklas 128     {
4264 14 Dec 16 nicklas 129       this.tmpFolderDebug = tmpFolder;
4264 14 Dec 16 nicklas 130     }
4264 14 Dec 16 nicklas 131     else
4264 14 Dec 16 nicklas 132     {
4264 14 Dec 16 nicklas 133       this.tmpFolder = tmpFolder;
4264 14 Dec 16 nicklas 134     }
4264 14 Dec 16 nicklas 135   }
4264 14 Dec 16 nicklas 136
4264 14 Dec 16 nicklas 137   /**
4257 30 Nov 16 nicklas 138     Get the command to execute for getting the current 
4212 08 Nov 16 nicklas 139     date and time from the cluster. 
4212 08 Nov 16 nicklas 140     The default command is: date +'%Y-%m-%d %T'
4212 08 Nov 16 nicklas 141   */
4212 08 Nov 16 nicklas 142   public String getDateCommand()
4212 08 Nov 16 nicklas 143   {
4212 08 Nov 16 nicklas 144     return dateCommand;
4212 08 Nov 16 nicklas 145   }
4212 08 Nov 16 nicklas 146   
4212 08 Nov 16 nicklas 147   /**
4212 08 Nov 16 nicklas 148     Set the command that should be executed to get the current
4212 08 Nov 16 nicklas 149     date and time from the cluster. It should return the date 
4212 08 Nov 16 nicklas 150     in format YYYY-MM-DD HH:MM:SS
4212 08 Nov 16 nicklas 151     
4212 08 Nov 16 nicklas 152     @throws IllegalStateException If this instance has been locked
4212 08 Nov 16 nicklas 153   */
4212 08 Nov 16 nicklas 154   public void setDateCommand(String dateCommand)
4212 08 Nov 16 nicklas 155   {
4212 08 Nov 16 nicklas 156     checkLocked("setDateCommand()");
4212 08 Nov 16 nicklas 157     this.dateCommand = dateCommand;
4212 08 Nov 16 nicklas 158   }
4257 30 Nov 16 nicklas 159
4257 30 Nov 16 nicklas 160   /**
4257 30 Nov 16 nicklas 161     Get the command to execute for getting some information
4257 30 Nov 16 nicklas 162     about the hardware and operating system of the host.
4257 30 Nov 16 nicklas 163     The default command is: uname -srmo
4257 30 Nov 16 nicklas 164   */
4257 30 Nov 16 nicklas 165   public String getHostInfoCommand()
4257 30 Nov 16 nicklas 166   {
4257 30 Nov 16 nicklas 167     return hostInfoCommand;
4257 30 Nov 16 nicklas 168   }
4254 25 Nov 16 nicklas 169   
4254 25 Nov 16 nicklas 170   /**
4257 30 Nov 16 nicklas 171     Set the command that should be executed to get some information
4257 30 Nov 16 nicklas 172     about the hardware and operating system of the host.
4257 30 Nov 16 nicklas 173     
4257 30 Nov 16 nicklas 174     @throws IllegalStateException If this instance has been locked
4257 30 Nov 16 nicklas 175   */
4257 30 Nov 16 nicklas 176   public void setHostInfoCommand(String hostInfoCommand)
4257 30 Nov 16 nicklas 177   {
4257 30 Nov 16 nicklas 178     checkLocked("setHostInfoCommand()");
4257 30 Nov 16 nicklas 179     this.hostInfoCommand = hostInfoCommand;
4257 30 Nov 16 nicklas 180   }
4257 30 Nov 16 nicklas 181
4257 30 Nov 16 nicklas 182   /**
4257 30 Nov 16 nicklas 183     Get the command to execute for getting some information
5981 07 Jul 20 nicklas 184     about the cluster manager software version.
5981 07 Jul 20 nicklas 185     The default command is: qstat -help | head -n1 (OpenGrid)
5981 07 Jul 20 nicklas 186     or: sinfo -V (Slurm)
4257 30 Nov 16 nicklas 187   */
4257 30 Nov 16 nicklas 188   public String getOpenGridInfoCommand()
4257 30 Nov 16 nicklas 189   {
4257 30 Nov 16 nicklas 190     return ogsInfoCommand;
4257 30 Nov 16 nicklas 191   }
4257 30 Nov 16 nicklas 192   
4257 30 Nov 16 nicklas 193   /**
4257 30 Nov 16 nicklas 194     Set the command that should be executed to get some information
5981 07 Jul 20 nicklas 195     about the cluster manager software version.
4257 30 Nov 16 nicklas 196     
4257 30 Nov 16 nicklas 197     @throws IllegalStateException If this instance has been locked
4257 30 Nov 16 nicklas 198   */
4257 30 Nov 16 nicklas 199   public void setOpenGridInfoCommand(String ogsInfoCommand)
4257 30 Nov 16 nicklas 200   {
4257 30 Nov 16 nicklas 201     checkLocked("setOpenGridInfoCommand()");
4257 30 Nov 16 nicklas 202     this.ogsInfoCommand = ogsInfoCommand;
4257 30 Nov 16 nicklas 203   }
4257 30 Nov 16 nicklas 204
4257 30 Nov 16 nicklas 205   /**
4255 28 Nov 16 nicklas 206     Get the External ID of the job agent this cluster
4255 28 Nov 16 nicklas 207     should be linked to. If null, this cluster is not
4255 28 Nov 16 nicklas 208     linked with any job agent and may be used by all.
4255 28 Nov 16 nicklas 209   */
4255 28 Nov 16 nicklas 210   public String getJobAgentExternalId()
4255 28 Nov 16 nicklas 211   {
4255 28 Nov 16 nicklas 212     return jobAgentExternalId;
4255 28 Nov 16 nicklas 213   }
4255 28 Nov 16 nicklas 214   
4255 28 Nov 16 nicklas 215   /**
4255 28 Nov 16 nicklas 216     Set the External ID of the job agent this cluster 
4255 28 Nov 16 nicklas 217     should be linked to. Job agents are used as placeholders
4255 28 Nov 16 nicklas 218     for setting up access control to Open Grid clusters.
4255 28 Nov 16 nicklas 219     
4255 28 Nov 16 nicklas 220     @throws IllegalStateException If this instance has been locked
4255 28 Nov 16 nicklas 221   */
4255 28 Nov 16 nicklas 222   public void setJobAgentExternalId(String jobAgentExternalId)
4255 28 Nov 16 nicklas 223   {
4255 28 Nov 16 nicklas 224     checkLocked("setJobAgentExternalId()");
4255 28 Nov 16 nicklas 225     this.jobAgentExternalId = jobAgentExternalId;
4255 28 Nov 16 nicklas 226   }
4255 28 Nov 16 nicklas 227
4255 28 Nov 16 nicklas 228   /**
4275 19 Dec 16 nicklas 229     Add the name of a node in the cluster. The node
4275 19 Dec 16 nicklas 230     list of nodes may be used for special actions.
4275 19 Dec 16 nicklas 231   */
4275 19 Dec 16 nicklas 232   public void addNode(NodeConfig node)
4275 19 Dec 16 nicklas 233   {
4275 19 Dec 16 nicklas 234     checkLocked("addNode()");
4275 19 Dec 16 nicklas 235     this.nodes.add(node.lock());
4275 19 Dec 16 nicklas 236   }
4275 19 Dec 16 nicklas 237   
4275 19 Dec 16 nicklas 238   /**
4275 19 Dec 16 nicklas 239     Get all configured nodes.
4275 19 Dec 16 nicklas 240   */
4275 19 Dec 16 nicklas 241   public List<NodeConfig> getNodes()
4275 19 Dec 16 nicklas 242   {
4275 19 Dec 16 nicklas 243     return Collections.unmodifiableList(nodes);
4275 19 Dec 16 nicklas 244   }
4275 19 Dec 16 nicklas 245   
4275 19 Dec 16 nicklas 246   /**
6827 31 Aug 22 nicklas 247     Set a custom option for the cluster.
6827 31 Aug 22 nicklas 248     @since 1.7
6827 31 Aug 22 nicklas 249   */
6827 31 Aug 22 nicklas 250   public void setCustomOption(String key, String value)
6827 31 Aug 22 nicklas 251   {
6827 31 Aug 22 nicklas 252     checkLocked("setOption("+key+")");
6827 31 Aug 22 nicklas 253     this.customOptions.put(key, value);
6827 31 Aug 22 nicklas 254   }
6827 31 Aug 22 nicklas 255   
6827 31 Aug 22 nicklas 256   /**
6827 31 Aug 22 nicklas 257     Get a custom option for the cluster.
6827 31 Aug 22 nicklas 258     @since 1.7
6827 31 Aug 22 nicklas 259   */
6827 31 Aug 22 nicklas 260   public String getCustomOption(String key)
6827 31 Aug 22 nicklas 261   {
6827 31 Aug 22 nicklas 262     return customOptions.get(key);
6827 31 Aug 22 nicklas 263   }
6827 31 Aug 22 nicklas 264   
6827 31 Aug 22 nicklas 265   /**
6827 31 Aug 22 nicklas 266     Get all custom option for the cluster. The returned
6827 31 Aug 22 nicklas 267     map is locked for modifications.
6827 31 Aug 22 nicklas 268     @since 1.7
6827 31 Aug 22 nicklas 269   */
6827 31 Aug 22 nicklas 270   public Map<String, String> getCustomOptions()
6827 31 Aug 22 nicklas 271   {
6827 31 Aug 22 nicklas 272     return Collections.unmodifiableMap(customOptions);
6827 31 Aug 22 nicklas 273   }
6827 31 Aug 22 nicklas 274   
6827 31 Aug 22 nicklas 275   /**
4254 25 Nov 16 nicklas 276     Job folder and date command are required.
4254 25 Nov 16 nicklas 277    */
4254 25 Nov 16 nicklas 278   @Override
4257 30 Nov 16 nicklas 279   protected void checkValid(boolean forLock) 
4254 25 Nov 16 nicklas 280   {
4257 30 Nov 16 nicklas 281     super.checkValid(forLock);
4254 25 Nov 16 nicklas 282     if (jobFolder == null) throw new NullPointerException("jobFolder");
4264 14 Dec 16 nicklas 283     if (tmpFolder == null) throw new NullPointerException("tmpFolder");
4254 25 Nov 16 nicklas 284     if (dateCommand == null) throw new NullPointerException("dateCommand");
4257 30 Nov 16 nicklas 285     if (hostInfoCommand == null) throw new NullPointerException("hostInfoCommand");
4257 30 Nov 16 nicklas 286     if (ogsInfoCommand == null) throw new NullPointerException("ogsInfoCommand");
4254 25 Nov 16 nicklas 287   }
4126 26 Sep 16 nicklas 288
4257 30 Nov 16 nicklas 289   /**
4296 12 Jan 17 nicklas 290     Get the configuration information as a JSON object. The following
4296 12 Jan 17 nicklas 291     information is returned by default:
4296 12 Jan 17 nicklas 292     
5981 07 Jul 20 nicklas 293     - type
4317 23 Jan 17 nicklas 294     - jobAgent.externalId *
4296 12 Jan 17 nicklas 295     - jobFolder
4296 12 Jan 17 nicklas 296     - tmpFolder
4296 12 Jan 17 nicklas 297     - tmpFolderDebug
4296 12 Jan 17 nicklas 298     - dateCommand
4296 12 Jan 17 nicklas 299     - hostInfoCommand
4296 12 Jan 17 nicklas 300     - ogsInfoCommand
4296 12 Jan 17 nicklas 301     
4296 12 Jan 17 nicklas 302     If the {@link JSONOption#NODE_INFO} is enabled:
4296 12 Jan 17 nicklas 303     - nodes: array with node names
4317 23 Jan 17 nicklas 304     
6827 31 Aug 22 nicklas 305     If the {@link JSONOption#CUSTOM_OPTIONS} is enabled:
6827 31 Aug 22 nicklas 306     - options: object with all custom options
6827 31 Aug 22 nicklas 307     
4317 23 Jan 17 nicklas 308     (*) The 'jobAgent' is a sub-object that is only included
4317 23 Jan 17 nicklas 309     if the job agent external id has been set. If
4317 23 Jan 17 nicklas 310     {@link JSONOption#JOBAGENT_INFO} is enabled additional
4317 23 Jan 17 nicklas 311     information is loaded from the database:
4317 23 Jan 17 nicklas 312     
4317 23 Jan 17 nicklas 313     - jobAgent.id
4317 23 Jan 17 nicklas 314     - jobAgent.name
4317 23 Jan 17 nicklas 315     - jobAgent.isShared
4317 23 Jan 17 nicklas 316     - jobAgent.exception (only if there is some problem loading the information)
4257 30 Nov 16 nicklas 317   */
4257 30 Nov 16 nicklas 318   public JSONObject asJSONObject(JSONOptions options)
4257 30 Nov 16 nicklas 319   {
4257 30 Nov 16 nicklas 320     JSONObject json = new JSONObject();
5981 07 Jul 20 nicklas 321     json.put("type", type.name());
4317 23 Jan 17 nicklas 322     JSONObject jsonJobAgent = new JSONObject();
4317 23 Jan 17 nicklas 323     if (jobAgentExternalId != null)
4317 23 Jan 17 nicklas 324     {
4317 23 Jan 17 nicklas 325       jsonJobAgent.put("externalId", jobAgentExternalId);
4317 23 Jan 17 nicklas 326       json.put("jobAgent", jsonJobAgent);
4317 23 Jan 17 nicklas 327     }
4257 30 Nov 16 nicklas 328     json.put("jobFolder", jobFolder);
4264 14 Dec 16 nicklas 329     json.put("tmpFolder", tmpFolder);
4264 14 Dec 16 nicklas 330     json.put("tmpFolderDebug", tmpFolderDebug);
4257 30 Nov 16 nicklas 331     json.put("dateCommand", dateCommand);
4257 30 Nov 16 nicklas 332     json.put("hostInfoCommand", hostInfoCommand);
4257 30 Nov 16 nicklas 333     json.put("ogsInfoCommand", ogsInfoCommand);
4275 19 Dec 16 nicklas 334     if (options.isEnabled(JSONOption.NODE_INFO))
4275 19 Dec 16 nicklas 335     {
4275 19 Dec 16 nicklas 336       JSONArray jsonNodes = new JSONArray();
4275 19 Dec 16 nicklas 337       for (NodeConfig node : nodes)
4275 19 Dec 16 nicklas 338       {
4275 19 Dec 16 nicklas 339         jsonNodes.add(node.asJSONObject(options));
4275 19 Dec 16 nicklas 340       }
4275 19 Dec 16 nicklas 341       json.put("nodes", jsonNodes);
4275 19 Dec 16 nicklas 342     }
6827 31 Aug 22 nicklas 343     if (options.isEnabled(JSONOption.CUSTOM_OPTIONS))
6827 31 Aug 22 nicklas 344     {
6827 31 Aug 22 nicklas 345       JSONObject jsonOptions = new JSONObject();
6827 31 Aug 22 nicklas 346       jsonOptions.putAll(customOptions);
6827 31 Aug 22 nicklas 347       json.put("options", jsonOptions);
6827 31 Aug 22 nicklas 348     }
4317 23 Jan 17 nicklas 349     if (options.isEnabled(JSONOption.JOBAGENT_INFO))
4317 23 Jan 17 nicklas 350     {
4317 23 Jan 17 nicklas 351       DbControl dc = options.getDbControl();
4317 23 Jan 17 nicklas 352       if (dc != null && jobAgentExternalId != null)
4317 23 Jan 17 nicklas 353       {
4317 23 Jan 17 nicklas 354         try
4317 23 Jan 17 nicklas 355         {
4317 23 Jan 17 nicklas 356           JobAgent agent = JobAgent.getByExternalId(dc, jobAgentExternalId);
4317 23 Jan 17 nicklas 357           jsonJobAgent.put("id", agent.getId());
4317 23 Jan 17 nicklas 358           jsonJobAgent.put("name", agent.getName());
4317 23 Jan 17 nicklas 359           jsonJobAgent.put("isShared", agent.isShared());
4317 23 Jan 17 nicklas 360         }
4317 23 Jan 17 nicklas 361         catch (RuntimeException ex)
4317 23 Jan 17 nicklas 362         {
4317 23 Jan 17 nicklas 363           jsonJobAgent.put("exception", ex.getMessage());
4317 23 Jan 17 nicklas 364         }
4317 23 Jan 17 nicklas 365       }
4317 23 Jan 17 nicklas 366     }
4257 30 Nov 16 nicklas 367     return json;
4257 30 Nov 16 nicklas 368   }
4257 30 Nov 16 nicklas 369
4126 26 Sep 16 nicklas 370 }