001/* An actor that delays the the execution of the model until a specified time.
002
003 Copyright (c) 2006-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.actor.lib;
029
030import java.text.DateFormat;
031import java.text.ParseException;
032import java.util.Calendar;
033import java.util.Date;
034
035import ptolemy.actor.Director;
036import ptolemy.actor.TypedAtomicActor;
037import ptolemy.data.expr.StringParameter;
038import ptolemy.kernel.CompositeEntity;
039import ptolemy.kernel.util.IllegalActionException;
040import ptolemy.kernel.util.NameDuplicationException;
041
042///////////////////////////////////////////////////////////////////
043//// DelayStart
044
045/**
046 This actor, which has no ports, delays the execution of the model
047 until a specified time by sleeping the thread that calls the
048 initialize() method until the specified time. If the time is
049 in the past, then there is no delay. The time is assumed to be
050 today, and is given as in "1:00 pm" for one in the afternoon.
051 <p>
052 If this actor is used in SDF, then the director must be set
053 to allow disconnected graphs.  Note that it makes no sense
054 to use this actor in PN or CSP, since it will only delay the
055 start of its own thread.
056
057 @author Edward A. Lee
058 @version $Id$
059 @since Ptolemy II 5.2
060
061 @Pt.ProposedRating Yellow (eal)
062 @Pt.AcceptedRating Red (cxh)
063 */
064public class DelayStart extends TypedAtomicActor {
065    /** Construct an actor with the given container and name.
066     *  @param container The container.
067     *  @param name The name of this actor.
068     *  @exception IllegalActionException If the actor cannot be contained
069     *   by the proposed container.
070     *  @exception NameDuplicationException If the container already has an
071     *   actor with this name.
072     */
073    public DelayStart(CompositeEntity container, String name)
074            throws NameDuplicationException, IllegalActionException {
075        super(container, name);
076
077        startTime = new StringParameter(this, "startTime");
078        startTime.setExpression("12:00 pm");
079    }
080
081    ///////////////////////////////////////////////////////////////////
082    ////                     ports and parameters                  ////
083
084    /** The start time. FIXME: Spec.
085     *  This is a string that defaults to FIXME
086     */
087    public StringParameter startTime;
088
089    ///////////////////////////////////////////////////////////////////
090    ////                         public methods                    ////
091
092    /** Sleep until the specified time.
093     *  @exception IllegalActionException If the parent class throws it,
094     *   or if the time cannot be parsed.
095     */
096    @Override
097    public void initialize() throws IllegalActionException {
098        DateFormat dateFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
099
100        try {
101            while (true) {
102                Date date = dateFormat.parse(startTime.stringValue());
103
104                // Unfortunately, in the above, if no date is given,
105                // then the time is assumed to be on January 1, 1970.
106                // Detect this, and reset the date to today.
107                Calendar calendar = Calendar.getInstance();
108                calendar.setTime(date);
109
110                if (calendar.get(Calendar.YEAR) == 1970) {
111                    // Assume the date wasn't set.
112                    Calendar now = Calendar.getInstance();
113                    calendar.set(Calendar.YEAR, now.get(Calendar.YEAR));
114                    calendar.set(Calendar.DAY_OF_MONTH,
115                            now.get(Calendar.DAY_OF_MONTH));
116                    calendar.set(Calendar.MONTH, now.get(Calendar.MONTH));
117                    date = calendar.getTime();
118                }
119
120                if (_debugging) {
121                    _debug("Delaying start until: " + date);
122                }
123
124                long time = date.getTime();
125                Director director = getDirector();
126                long current = System.currentTimeMillis();
127
128                if (time <= current) {
129                    break;
130                }
131
132                // Synchronizing on the director here is incorrect.
133                // See Workspace.wait(Object)
134                // synchronized (director) {
135                try {
136                    _workspace.wait(director, time - current);
137                } catch (InterruptedException e) {
138                    // Ignore and continue;
139                }
140                // }
141            }
142        } catch (ParseException e) {
143            throw new IllegalActionException(this,
144                    "Invalid startTime: " + startTime.stringValue());
145        }
146
147        super.initialize();
148    }
149}