001/*
002 * Copyright (c) 2004-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
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.ssh;
031
032import org.apache.commons.logging.Log;
033import org.apache.commons.logging.LogFactory;
034import org.kepler.ssh.ExecException;
035import org.kepler.ssh.ExecFactory;
036import org.kepler.ssh.ExecInterface;
037
038import ptolemy.actor.TypedAtomicActor;
039import ptolemy.actor.TypedIOPort;
040import ptolemy.actor.parameters.PortParameter;
041import ptolemy.data.BooleanToken;
042import ptolemy.data.StringToken;
043import ptolemy.data.expr.Parameter;
044import ptolemy.data.type.BaseType;
045import ptolemy.kernel.CompositeEntity;
046import ptolemy.kernel.util.IllegalActionException;
047import ptolemy.kernel.util.NameDuplicationException;
048
049//////////////////////////////////////////////////////////////////////////
050//// DirectoryCreator
051
052/**
053 * <p>
054 * Actor for creating a local/remote directory.
055 * </p>
056 * 
057 * <p>
058 * The input should define:
059 * <ul>
060 * <li>the target machine, either "" or "local" to denote the local machine to
061 * be used by Java I/O commands, OR "[user@]host[:port]" to denote a remote
062 * machine to be used by an ssh connection.</li>
063 * <li>the directory to be created (given as String).</li>
064 * </ul>
065 * 
066 * </p>
067 * <p>
068 * A relative path is relative to the home directory in case of remote
069 * operations and relative to the current directory in case of local operations.
070 * 
071 * </p>
072 * <p>
073 * The actor creates the directory and emits 'true' on the 'succ' port if it is
074 * successful. On the 'error' port, an empty string is emitted, so that this
075 * actor can be used under SDF.
076 * 
077 * </p>
078 * <p>
079 * On error, 'false' is emitted on 'succ' and the error output of the commands
080 * on the 'error' port.
081 * 
082 * </p>
083 * <p>
084 * If the 'parent' flag is set the operation is considered to be successful even
085 * if the directory already exists. Intermediate directories in the provided
086 * path will be created if necessary (as the 'mkdir -p' unix command and the
087 * File.mkdirs() method work).
088 * 
089 * </p>
090 * <p>
091 * This actor uses org.kepler.ssh.SshExec class to create a remote directory or
092 * org.kepler.ssh.LocalExec class to create a local directory.In the first case,
093 * the unix command "mkdir" or "mkdir -p" is used, depending on the parent flag.
094 * In the latter case, File.mkdir() or File.mkdirs() method is used to create
095 * the directory.
096 * </p>
097 * 
098 * @author Norbert Podhorszki
099 * @version $Id: DirectoryCreator.java 24234 2010-05-06 05:21:26Z welker $
100 * @since Ptolemy II 5.0.1
101 */
102public class DirectoryCreator extends TypedAtomicActor {
103        /**
104         * Construct an actor with the given container and name.
105         * 
106         * @param container
107         *            The container.
108         * @param name
109         *            The name of this actor.
110         * @exception IllegalActionException
111         *                If the actor cannot be contained by the proposed
112         *                container.
113         * @exception NameDuplicationException
114         *                If the container already has an actor with this name.
115         */
116        public DirectoryCreator(CompositeEntity container, String name)
117                        throws NameDuplicationException, IllegalActionException {
118                super(container, name);
119
120                // Uncomment the next line to see debugging statements
121                // addDebugListener(new ptolemy.kernel.util.StreamListener());
122
123                // target selects the machine where the directory is to be accessed
124                target = new PortParameter(this, "target", new StringToken(
125                                "[ local | [user@]host[:port] ]"));
126                new Parameter(target.getPort(), "_showName", BooleanToken.TRUE);
127
128                // dir is the path to the directory to be listed on the target machine
129                dir = new PortParameter(this, "dir", new StringToken("/path/to/dir"));
130                new Parameter(dir.getPort(), "_showName", BooleanToken.TRUE);
131
132                // parent parameter
133                parent = new Parameter(this, "parent", new BooleanToken(true));
134                parent.setTypeEquals(BaseType.BOOLEAN);
135
136                /*
137                 * Output ports
138                 */
139
140                succ = new TypedIOPort(this, "succ", false, true);
141                succ.setTypeEquals(BaseType.BOOLEAN);
142                new Parameter(succ, "_showName", BooleanToken.TRUE);
143
144                error = new TypedIOPort(this, "error", false, true);
145                error.setTypeEquals(BaseType.STRING);
146                new Parameter(error, "_showName", BooleanToken.TRUE);
147
148                _attachText("_iconDescription", "<svg>\n" + "<rect x=\"0\" y=\"0\" "
149                                + "width=\"75\" height=\"50\" style=\"fill:blue\"/>\n"
150                                + "<text x=\"5\" y=\"30\""
151                                + "style=\"font-size:14; fill:yellow; font-family:SansSerif\">"
152                                + "SshExec</text>\n" + "</svg>\n");
153
154        }
155
156        /***********************************************************
157         * ports and parameters
158         */
159
160        /**
161         * The machine to be used at job submission. It should be null, "" or
162         * "local" for the local machine or [user@]host[:port] to denote a remote
163         * machine accessible with ssh.
164         * 
165         * This parameter is read once at initialize.
166         */
167        public PortParameter target;
168
169        /**
170         * The path to the directory to be read on the target machines. This
171         * parameter is read once at initialize.
172         */
173        public PortParameter dir;
174
175        /**
176         * Specifying whether parent directories should be created recursively if
177         * necessary.
178         */
179        public Parameter parent;
180
181        /**
182         * The flag of successful operation. It is a port of type Boolean token.
183         */
184        public TypedIOPort succ;
185
186        /**
187         * The string representation of all the errors that happened during the
188         * execution of the actor, if there are any, otherwise an empty string. A
189         * port of type String token.
190         */
191        public TypedIOPort error;
192
193        /***********************************************************
194         * public methods
195         */
196
197        /**
198         * initialize() runs once before first exec
199         * 
200         * @exception IllegalActionException
201         *                If the parent class throws it.
202         */
203        public void initialize() throws IllegalActionException {
204                super.initialize();
205        }
206
207        /**
208         * fire
209         * 
210         * @exception IllegalActionException
211         */
212        public void fire() throws IllegalActionException {
213                super.fire();
214
215                // update PortParameters
216                target.update();
217                dir.update();
218
219                _target = ((StringToken) target.getToken()).stringValue().trim();
220                _dir = ((StringToken) dir.getToken()).stringValue().trim();
221                _parent = ((BooleanToken) parent.getToken()).booleanValue();
222
223                if (isDebugging)
224                        log.debug("Create Directory: " + "target = " + _target + "; dir = "
225                                        + _dir + "; parent = " + _parent);
226
227
228                // execute the directory create command
229                boolean _succ;
230                String _error;
231                try {
232                        
233                        // get the actual execution object (local or remote)
234                        ExecInterface execObj = ExecFactory.getExecObject(_target);
235                        _succ = execObj.createDir(_dir, _parent);
236
237                        if (isDebugging)
238                                log
239                                                .debug(_succ ? "Directory created: " + _target + ":"
240                                                                + _dir : "Directory operation failed: "
241                                                                + _target + ":" + _dir);
242                        _error = new String("");
243
244                }catch (ExecException ex) {
245                        _error = new String(
246                                        "DirectoryCreator error when creating directory " + _target
247                                                        + ":" + _dir + ".\n" + ex);
248                        _succ = false;
249                        log.error(_error);
250                }
251
252                succ.send(0, new BooleanToken(_succ));
253                error.send(0, new StringToken(_error));
254
255        }
256
257        private String _target;
258        private String _dir;
259        private boolean _parent;
260
261        private static final Log log = LogFactory.getLog(DirectoryCreator.class
262                        .getName());
263        private static final boolean isDebugging = log.isDebugEnabled();
264
265}