001/* A timed actor that outputs a const value at a given date. 002 003 Copyright (c) 1998-2015 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 */ 028 029package ptolemy.domains.de.lib; 030 031import java.util.ArrayList; 032import java.util.Collections; 033import java.util.HashMap; 034import java.util.List; 035 036import ptolemy.actor.CompositeActor; 037import ptolemy.actor.Director; 038import ptolemy.actor.Manager; 039import ptolemy.actor.lib.Transformer; 040import ptolemy.actor.util.Time; 041import ptolemy.data.BooleanToken; 042import ptolemy.data.DateToken; 043import ptolemy.data.type.BaseType; 044import ptolemy.domains.de.kernel.DEDirector; 045import ptolemy.kernel.CompositeEntity; 046import ptolemy.kernel.util.IllegalActionException; 047import ptolemy.kernel.util.NameDuplicationException; 048 049/** A timed actor that accepts DateTokens on the input. If the date in 050 * the DateToken is in the future, the output is generated at this 051 * future date. If the date is in the past, an exception is thrown. 052 * The output is a DateToken with the system time obtained when producing 053 * the output. Internally, the input date is converted to model time, which 054 * is used in the local clock of the director. 055 * Because we are using system time here, the output time will not be 056 * exact and the output DateToken will not be exactly the same as the 057 * DateToken received on the input. 058 * 059 * Using this actor makes sense in models that synchronize to real time 060 * (e.g. in the DE domain by enabling the synchronizeToRealTime property). 061 * @author Patricia Derler 062 * @version $Id$ 063 * @since Ptolemy II 10.0 064 * @version $Id$ 065 * @Pt.ProposedRating Red (cxh) 066 * @Pt.AcceptedRating Red (cxh) 067 */ 068public class DateToEvent extends Transformer { 069 070 /** Create a new actor in the specified container with the specified 071 * name. The name must be unique within the container or an exception 072 * is thrown. The container argument must not be null, or a 073 * NullPointerException will be thrown. 074 * 075 * @param container The container. 076 * @param name The name of this actor within the container. 077 * @exception IllegalActionException If this actor cannot be contained 078 * by the proposed container (see the setContainer() method). 079 * @exception NameDuplicationException If the name coincides with 080 * an entity already in the container. 081 */ 082 public DateToEvent(CompositeEntity container, String name) 083 throws IllegalActionException, NameDuplicationException { 084 super(container, name); 085 input.setTypeEquals(BaseType.DATE); 086 output.setTypeEquals(BaseType.DATE); 087 } 088 089 /** Check weather enclosing director is a DEDirector with 090 * synchronizeToRealTime is enabled. 091 * @exception IllegalActionException Thrown if the enclosing director is not a 092 * DEDirector or the synchronizeToRealTime property is false. 093 */ 094 @Override 095 public void initialize() throws IllegalActionException { 096 super.initialize(); 097 Director director = getDirector(); 098 if (director instanceof DEDirector) { 099 if (!((BooleanToken) ((DEDirector) director).synchronizeToRealTime 100 .getToken()).booleanValue()) { 101 throw new IllegalActionException(this, 102 "This actor can only be used when synchronizeToRealTime " 103 + "in the director is enabled because a reference to real time is needed to compare " 104 + "dates."); 105 } 106 _director = (DEDirector) director; 107 } 108 } 109 110 /** Read date tokens from the input and store them until the real 111 * time equals the date in the token. If the date token on the input 112 * contains a date in the past, an exception is thrown. 113 * @exception IllegalActionException Thrown if the input date in the date 114 * token lies in the past. 115 */ 116 @Override 117 public void fire() throws IllegalActionException { 118 super.fire(); 119 long systemTime = System.currentTimeMillis(); 120 if (_debugging) { 121 _debug("System time: " + systemTime); 122 } 123 Time time = _director.getModelTime(); 124 if (_outputTokensForChannel != null 125 && _outputTokensForChannel.size() > 0) { 126 Time t = (Collections.min(_outputTokensForChannel.keySet())); 127 if (_debugging) { 128 _debug("at model time " + time 129 + " output tokens > 0 starting with " + t); 130 } 131 if (t.compareTo(time) == 0) { 132 List<Integer> channels = _outputTokensForChannel.get(t); 133 for (int i = 0; i < channels.size(); i++) { 134 output.send(channels.get(i), new DateToken(systemTime)); 135 } 136 _outputTokensForChannel.remove(t); 137 } 138 } 139 for (int channel = 0; channel < input.getWidth(); channel++) { 140 if (input.hasToken(0)) { 141 DateToken token = (DateToken) input.get(0); 142 if (token.getCalendarInstance() 143 .getTimeInMillis() < systemTime) { 144 throw new IllegalActionException(this, 145 "The date on the input port (" + token.toString() 146 + ") lies in the past."); 147 } else { 148 if (_manager == null) { 149 _manager = ((CompositeActor) getContainer()) 150 .getManager(); 151 } 152 long realTimeDifferenceInMillis = token 153 .getCalendarInstance().getTimeInMillis() 154 - _manager.getRealStartTime(); 155 Time fireTime = new Time(_director, 156 ((double) realTimeDifferenceInMillis / 1000)); // The default unit of time is seconds. 157 if (_debugging) { 158 _debug("director start time (ms): " 159 + _director.elapsedTimeSinceStart()); 160 _debug("real time difference (ms):" 161 + realTimeDifferenceInMillis); 162 _debug("Scheduling firing at (model time):" + fireTime); 163 } 164 _director.fireAt(this, fireTime); 165 if (_outputTokensForChannel == null) { 166 _outputTokensForChannel = new HashMap<Time, List<Integer>>(); 167 } 168 List<Integer> channels = _outputTokensForChannel 169 .get(fireTime); 170 if (channels == null) { 171 channels = new ArrayList<Integer>(); 172 } 173 channels.add(channel); 174 _outputTokensForChannel.put(fireTime, channels); 175 } 176 } 177 } 178 } 179 180 private HashMap<Time, List<Integer>> _outputTokensForChannel; 181 182 private DEDirector _director; 183 private Manager _manager; 184 185}