001/* An actor that handles an HttpRequest by producing an output and waiting for an input. 002 003 Copyright (c) 1997-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 */ 028 029package ptolemy.domains.de.test; 030 031import java.util.Collection; 032import java.util.LinkedList; 033 034import ptolemy.actor.IOPort; 035import ptolemy.actor.TypedAtomicActor; 036import ptolemy.actor.TypedIOPort; 037import ptolemy.actor.util.BreakCausalityInterface; 038import ptolemy.actor.util.CausalityInterface; 039import ptolemy.data.DoubleToken; 040import ptolemy.data.type.BaseType; 041import ptolemy.kernel.CompositeEntity; 042import ptolemy.kernel.util.IllegalActionException; 043import ptolemy.kernel.util.NameDuplicationException; 044 045/** A test actor illustrating a potential bug in DE in its 046 * handling of superdense time. In particular, 047 * the outputs of this actor have no causal dependence on the 048 * inputs, and hence no delay is needed in a feedback loop 049 * that feeds outputs back to the inputs. Inputs are read 050 * and processed in postfire(). However, if the output is 051 * fed directly back to an input, then the input used to be 052 * read <i>in the same iteration</i> in which the output 053 * was produced. If, however, there is an intervening actor 054 * in the feedback loop, then the input would be read 055 * <i>in the next iteration</i>. This leads to strange 056 * behavior where the presence of even a no-op actor (like 057 * a unit gain) changes the behavior of the model. 058 * <p> 059 * What is the solution here? 060 * <p> 061 * This actor first outputs nothing. In postfire(), it 062 * reads inputs and sums them, and if any inputs were present, 063 * it requests a new firing. In that firing, it produces the 064 * calculated sum. 065 * After 10 firings, it stops producing outputs. 066 * 067 * @author Edward A. Lee 068 * @version $Id$ 069 * @since Ptolemy II 10.0 070 * @Pt.ProposedRating Red (ltrnc) 071 * @Pt.AcceptedRating Red (ltrnc) 072 */ 073public class SuperdenseTimeTest extends TypedAtomicActor { 074 075 /** Create an instance of the actor. 076 * @param container The container 077 * @param name The name. 078 * @exception IllegalActionException If the superclass throws it. 079 * @exception NameDuplicationException If the super 080 */ 081 public SuperdenseTimeTest(CompositeEntity container, String name) 082 throws IllegalActionException, NameDuplicationException { 083 super(container, name); 084 085 // Ports 086 in1 = new TypedIOPort(this, "in1", true, false); 087 in1.setTypeEquals(BaseType.DOUBLE); 088 in2 = new TypedIOPort(this, "in2", true, false); 089 in2.setTypeEquals(BaseType.DOUBLE); 090 in3 = new TypedIOPort(this, "in3", true, false); 091 in3.setTypeEquals(BaseType.DOUBLE); 092 out = new TypedIOPort(this, "out", false, true); 093 out.setTypeEquals(BaseType.DOUBLE); 094 095 _inputPorts = new LinkedList<IOPort>(); 096 _inputPorts.add(in1); 097 _inputPorts.add(in2); 098 _inputPorts.add(in3); 099 } 100 101 /////////////////////////////////////////////////////////////////// 102 //// ports and parameters //// 103 104 /** The inputs and output. 105 */ 106 public TypedIOPort in1, in2, in3, out; 107 108 /////////////////////////////////////////////////////////////////// 109 //// public methods //// 110 111 /** Override the base class to return a causality interface that 112 * indicates that no output depends (immediately) on 113 * any input, and that also puts both input ports in an 114 * equivalence class. 115 * @return A representation of the dependencies between input ports 116 * and output ports. 117 */ 118 @Override 119 public CausalityInterface getCausalityInterface() { 120 if (_causalityInterface == null) { 121 _causalityInterface = new BreakCausalityInterface(this, 122 getDirector().defaultDependency()) { 123 @Override 124 public Collection<IOPort> equivalentPorts(IOPort input) { 125 return _inputPorts; 126 } 127 }; 128 } 129 return _causalityInterface; 130 } 131 132 /** Respond to an HTTP request. If there is a 133 * response at the input port, then record that 134 * response and notify the servlet thread that a response 135 * is ready. Otherwise, if the servlet has received 136 * an HTTP request, then produce on the output ports 137 * the details of the request. 138 * @exception IllegalActionException If sending the 139 * outputs fails. 140 */ 141 @Override 142 public synchronized void fire() throws IllegalActionException { 143 // The methods of the servlet are invoked in another 144 // thread, so we synchronize on this actor for mutual exclusion. 145 super.fire(); 146 if (_count < 10 && _value != null) { 147 out.send(0, _value); 148 _value = null; 149 } 150 } 151 152 /** Set the output value to 0.0. 153 * @exception IllegalActionException If the superclass throws it. 154 */ 155 @Override 156 public void initialize() throws IllegalActionException { 157 super.initialize(); 158 _value = null; 159 _count = 0; 160 } 161 162 /** Read the inputs and sum them. 163 * @return True if a stop has not been requested. 164 */ 165 @Override 166 public synchronized boolean postfire() throws IllegalActionException { 167 if (_debugging) { 168 _debug("Starting postfire."); 169 } 170 double result = 0.0; 171 boolean foundOne = false; 172 if (in1.hasToken(0)) { 173 result += ((DoubleToken) in1.get(0)).doubleValue(); 174 foundOne = true; 175 } 176 if (in2.hasToken(0)) { 177 result += ((DoubleToken) in2.get(0)).doubleValue(); 178 foundOne = true; 179 } 180 if (in3.hasToken(0)) { 181 result += ((DoubleToken) in3.get(0)).doubleValue(); 182 foundOne = true; 183 } 184 if (foundOne) { 185 _value = new DoubleToken(result); 186 getDirector().fireAtCurrentTime(this); 187 } 188 _count++; 189 return super.postfire(); 190 } 191 192 /////////////////////////////////////////////////////////////////// 193 //// private variables //// 194 195 /** The causality interface. */ 196 private CausalityInterface _causalityInterface; 197 198 /** Count of firings. */ 199 private int _count; 200 201 /** A collection of the two input ports, for use in the causality interface. */ 202 private Collection<IOPort> _inputPorts; 203 204 /** Value to produce in fire(). */ 205 private DoubleToken _value; 206}