001/*
002 * Copyright (c) 2004-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: jianwu $'
006 * '$Date: 2012-09-14 22:48:44 +0000 (Fri, 14 Sep 2012) $' 
007 * '$Revision: 30678 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.actor.job;
031
032import org.apache.commons.logging.Log;
033import org.apache.commons.logging.LogFactory;
034import org.kepler.job.Job;
035import org.kepler.job.JobException;
036import org.kepler.job.JobFactory;
037
038import ptolemy.actor.TypedAtomicActor;
039import ptolemy.actor.TypedIOPort;
040import ptolemy.actor.parameters.PortParameter;
041import ptolemy.data.ArrayToken;
042import ptolemy.data.BooleanToken;
043import ptolemy.data.ObjectToken;
044import ptolemy.data.StringToken;
045import ptolemy.data.expr.Parameter;
046import ptolemy.data.type.BaseType;
047import ptolemy.kernel.CompositeEntity;
048import ptolemy.kernel.util.IllegalActionException;
049import ptolemy.kernel.util.NameDuplicationException;
050
051//////////////////////////////////////////////////////////////////////////
052//// JobCreator
053
054/**
055 * <p>
056 * Create a job. It does not execute it!
057 * </p>
058 * <p>
059 * This actor uses the Job and JobFactory classes to create a job that can be
060 * submitted with JobSubmitter.
061 * </p>
062 * 
063 * <p>
064 * The cmdFile should be the path to the job submission file that you have
065 * created before. This is jobmanager specific! It can be empty, if you want the
066 * JobManager to create the submission file for the (later) selected JobManager.
067 * Note: this capability of the job managers classes is not implemented yet, so
068 * you have to feed here the job submission file (prepared in advance). The file
069 * can either local or remote. Indicate in cmdFileLocal which case holds.
070 * </p>
071 * 
072 * <p>
073 * Executable is the path to the executable if it is located on this local
074 * machine. It will be staged to the remote site (into the job's working
075 * directory) before job submission. If the executable is located on the remote
076 * site, do not give it here, and use its absolute path in your submission file.
077 * </p>
078 * 
079 * <p>
080 * The working directory is the path to the remote working directory in which
081 * you want the job's files to be created. It will be expanded with the job's
082 * unique id assigned by the JobFactory.
083 * </p>
084 * 
085 * <p>
086 * The array of inputfiles is the list of (local) inputfiles to be staged to the
087 * remote site before job submission.
088 * </p>
089 * 
090 * <p>
091 * The array of remotefiles is the list of remote input files that are to be
092 * copied into the job's working directory before job submission.
093 * </p>
094 * 
095 * <p>
096 * The output is the created job (of type Object) that can be used later to
097 * submit the job in JobSubmitter and query its status in JobStatus actor. It is
098 * null if job creation failed.
099 * </p>
100 * 
101 * @author Norbert Podhorszki
102 * @version $Id: JobCreator.java 30678 2012-09-14 22:48:44Z jianwu $
103 * @since Ptolemy II 5.0.1
104 */
105public class JobCreator extends TypedAtomicActor {
106        /**
107         * Construct an actor with the given container and name.
108         * 
109         * @param container
110         *            The container.
111         * @param name
112         *            The name of this actor.
113         * @exception IllegalActionException
114         *                If the actor cannot be contained by the proposed
115         *                container.
116         * @exception NameDuplicationException
117         *                If the container already has an actor with this name.
118         */
119        public JobCreator(CompositeEntity container, String name)
120                        throws NameDuplicationException, IllegalActionException {
121                super(container, name);
122
123                // Uncomment the next line to see debugging statements
124                // addDebugListener(new ptolemy.kernel.util.StreamListener());
125
126                // submission file parameter & port
127                cmdFile = new PortParameter(this, "cmdFile", new StringToken(
128                                "/path/to/job.submit"));
129                new Parameter(cmdFile.getPort(), "_showName", BooleanToken.TRUE);
130                cmdFile.setStringMode(true);
131
132                // local/remote submission file flag parameter
133                cmdFileLocal = new Parameter(this, "cmdFileLocal", new BooleanToken(
134                                true));
135                cmdFileLocal.setTypeEquals(BaseType.BOOLEAN);
136
137                // executable file's name parameter & port
138                executable = new PortParameter(this, "executable", new StringToken(""));
139                new Parameter(executable.getPort(), "_showName", BooleanToken.TRUE);
140                executable.setStringMode(true);
141
142                // working dir name parameter & port
143                workdir = new PortParameter(this, "workdir", new StringToken(
144                                ".kepler-hpcc"));
145                workdir.setStringMode(true);
146
147                new Parameter(workdir.getPort(), "_showName", BooleanToken.TRUE);
148
149                // list of input files' names parameter & port
150                inputfiles = new PortParameter(this, "inputfiles", new ArrayToken(
151                                BaseType.STRING));
152
153                new Parameter(inputfiles.getPort(), "_showName", BooleanToken.TRUE);
154
155                // list of remote input files' names parameter & port
156                remotefiles = new PortParameter(this, "remotefiles", new ArrayToken(
157                                BaseType.STRING));
158
159                new Parameter(remotefiles.getPort(), "_showName", BooleanToken.TRUE);
160
161                // Output: job object reference to the submitted job
162                job = new TypedIOPort(this, "job", false, true);
163                job.setTypeEquals(BaseType.OBJECT);
164                new Parameter(job, "_showName", BooleanToken.FALSE);
165        }
166
167        /***********************************************************
168         * ports and parameters
169         */
170
171        /**
172         * The submit file to be used at job submission. Absolute (or relative to
173         * current dir of Java) file path should be provided. Currently you have to
174         * prepare your submit file.
175         * 
176         * <p>
177         * This parameter is read each time in fire().
178         * </p>
179         */
180        public PortParameter cmdFile;
181
182        /**
183         * Specifying whether the cmdFile is locally stored or on the remote target.
184         * 
185         * <p>
186         * This parameter is read each time in fire().
187         * </p>
188         */
189        public Parameter cmdFileLocal;
190
191        /**
192         * The executable file to be used at job submission. Absolute path names, or
193         * relative to current dir of the running java virtual machine, should be
194         * provided. If it is "" then it is considered to be already at the remote
195         * site, otherwise the actor will look for it locally and stage it to the
196         * <i>workdir</i> before job submission.
197         * 
198         * <p>
199         * This parameter is read each time in fire().
200         * </p>
201         */
202        public PortParameter executable;
203
204        /**
205         * The working directory in which the actual job submission command will be
206         * executed (on the remote machine if the job manager is a remote
207         * jobmanager).
208         * 
209         * <p>
210         * It should be an absolute path, or a relative one. In the latter case on
211         * remote machine, the directory path will be relative to the user's home
212         * directory (coming from the use of ssh)
213         * </p>
214         * 
215         * <p>
216         * This parameter is read each time in fire().
217         * </p>
218         */
219        public PortParameter workdir;
220
221        /**
222         * The string array of inputfiles. Absolute path names, or relative to
223         * current dir of the running java virtual machine, should be provided.
224         * 
225         * <p>
226         * This parameter is read each time in fire().
227         * </p>
228         */
229        public PortParameter inputfiles;
230
231        /**
232         * The string array of remote input files. Absolute path names, or relative
233         * to the user home dir on the remote host should be provided.
234         * 
235         * <p>
236         * This parameter is read each time in fire().
237         * </p>
238         */
239        public PortParameter remotefiles;
240
241        /**
242         * The job object. It will be null if the job submission fails.
243         */
244        public TypedIOPort job;
245
246        /***********************************************************
247         * public methods
248         */
249
250        /**
251         * fire
252         * 
253         * @exception IllegalActionException
254         *                Not thrown.
255         */
256        public void fire() throws IllegalActionException {
257                super.fire();
258
259                cmdFile.update();
260                executable.update();
261                workdir.update();
262                inputfiles.update();
263                remotefiles.update();
264
265                String strCmdFile = ((StringToken) cmdFile.getToken()).stringValue();
266                boolean bCmdFileLocal = ((BooleanToken) cmdFileLocal.getToken())
267                                .booleanValue();
268
269                String strExecutable = ((StringToken) executable.getToken())
270                                .stringValue();
271                String strWorkdir = ((StringToken) workdir.getToken()).stringValue();
272                
273                //back compatibility, remove the double quotes at the very beginning and at the very last.
274                strWorkdir  = strWorkdir.replaceAll("^\"|\"$", "");
275                strExecutable  = strExecutable.replaceAll("^\"|\"$", "");
276                strCmdFile  = strCmdFile.replaceAll("^\"|\"$", "");
277
278                // Process the inputfiles parameter.
279                ArrayToken inputTokens = (ArrayToken) inputfiles.getToken();
280                String[] inputArray = null;
281                if (inputTokens.length() >= 1) {
282                        inputArray = new String[inputTokens.length()];
283                        int i;
284                        for (i = 0; i < inputTokens.length(); i++) {
285                                inputArray[i] = (((StringToken) inputTokens.getElement(i))
286                                                .stringValue());
287                        }
288                        // process empty array
289                        if (i == 0 || inputArray[0] == "")
290                                inputArray = null;
291                }
292
293                // Process the remotefiles parameter.
294                ArrayToken remoteTokens = (ArrayToken) remotefiles.getToken();
295                String[] remoteArray = null;
296                if (remoteTokens.length() >= 1) {
297                        remoteArray = new String[remoteTokens.length()];
298                        int i;
299                        for (i = 0; i < remoteTokens.length(); i++) {
300                                remoteArray[i] = (((StringToken) remoteTokens.getElement(i))
301                                                .stringValue());
302                        }
303                        // process empty array
304                        if (i == 0 || remoteArray[0] == "")
305                                remoteArray = null;
306                }
307
308                // create job
309                String strJobID = JobFactory.create();
310                Job _job = JobFactory.get(strJobID);
311
312                try {
313                        // set _job's executable, working dir and input files
314                        if (strExecutable != null && strExecutable.trim().length() > 0)
315                                _job.setExecutable(strExecutable, true, "");
316
317                        if (strWorkdir != null && strWorkdir.trim().length() > 0)
318                                _job.setWorkdir(strWorkdir);
319
320                        if (strCmdFile != null && strCmdFile.trim().length() > 0)
321                                _job.setSubmitFile(strCmdFile, bCmdFileLocal);
322
323                        if (inputArray != null) {
324                                for (int i = 0; i < inputArray.length; i++) {
325                                        if (inputArray[i] != null
326                                                        && inputArray[i].trim().length() > 0)
327                                                _job.setInputFile(inputArray[i], true);
328                                }
329                        }
330
331                        if (remoteArray != null) {
332                                for (int i = 0; i < remoteArray.length; i++) {
333                                        if (remoteArray[i] != null
334                                                        && remoteArray[i].trim().length() > 0)
335                                                _job.setInputFile(remoteArray[i], false);
336                                }
337                        }
338
339                } catch (JobException ex) {
340                        log.error(ex);
341                        JobFactory.remove(strJobID);
342                        strJobID = "";
343                        _job = null;
344                        ex.printStackTrace();
345                        throw new IllegalActionException("JobCreator Error: " + ex.toString());
346                }
347
348                job.send(0, new ObjectToken(_job));
349        }
350
351        private static final Log log = LogFactory
352                        .getLog(JobCreator.class.getName());
353        private static final boolean isDebugging = log.isDebugEnabled();
354
355}