001/* An actor that throws a model error when it receives a true token.
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 */
028package ptolemy.actor.lib;
029
030import ptolemy.actor.InvariantViolationException;
031import ptolemy.data.BooleanToken;
032import ptolemy.data.expr.Parameter;
033import ptolemy.data.type.BaseType;
034import ptolemy.kernel.CompositeEntity;
035import ptolemy.kernel.util.IllegalActionException;
036import ptolemy.kernel.util.NameDuplicationException;
037import ptolemy.kernel.util.NamedObj;
038import ptolemy.kernel.util.StringAttribute;
039
040///////////////////////////////////////////////////////////////////
041//// ThrowModelError
042
043/**
044 <p>An actor that throws a model error when it receives a true token
045 on any input channel.  The message reported in the model error is
046 given by the <i>message</i> parameter.
047 The inputs are read and checked in the postfire() method only.
048 </p><p>
049 A model error is an exception that is passed up the containment
050 hierarchy rather than being immediately thrown. Any container
051 in the containment hierarchy may choose to handle the error.
052 By default, containers will pass and delegate the error to their
053 container, if they have one, and throw an exception if they
054 don't. But some containers might do more with the error.</p>
055
056 @author Haiyang Zheng
057 @version $Id$
058 @since Ptolemy II 2.1
059 @Pt.ProposedRating Green (eal)
060 @Pt.AcceptedRating Green (neuendor)
061 @see ThrowException
062 @see ptolemy.kernel.util.NamedObj#handleModelError(NamedObj, IllegalActionException)
063 */
064public class ThrowModelError extends Sink {
065    /** Construct an actor in the specified container with the specified
066     *  name.
067     *  @param container The container.
068     *  @param name The name of this actor within the container.
069     *  @exception IllegalActionException If the actor cannot be contained
070     *   by the proposed container.
071     *  @exception NameDuplicationException If the name coincides with
072     *   an actor already in the container.
073     */
074    public ThrowModelError(CompositeEntity container, String name)
075            throws IllegalActionException, NameDuplicationException {
076        super(container, name);
077
078        input.setTypeEquals(BaseType.BOOLEAN);
079
080        message = new StringAttribute(this, "message");
081        message.setExpression("A model error.");
082
083        throwInPostfire = new Parameter(this, "throwInPostfire");
084        throwInPostfire.setTypeEquals(BaseType.BOOLEAN);
085        throwInPostfire.setExpression("false");
086    }
087
088    ///////////////////////////////////////////////////////////////////
089    ////                     ports and parameters                  ////
090
091    /** The message reported in the exception. */
092    public StringAttribute message;
093
094    /** True to throw the model error in the postfire method.
095     *  False to throw in fire. This is a boolean that defaults
096     *  to false.
097     */
098    public Parameter throwInPostfire;
099
100    ///////////////////////////////////////////////////////////////////
101    ////                         public methods                    ////
102
103    /** Read one token from each input channel that has a token,
104     *  and if any token is true, invoke the model error handler.
105     *  @exception IllegalActionException If thrown by the parent class.
106     */
107    @Override
108    public void fire() throws IllegalActionException {
109        super.fire();
110        if (!((BooleanToken) throwInPostfire.getToken()).booleanValue()) {
111            boolean result = false;
112
113            // NOTE: We need to consume data on all channels that have data.
114            // If we don't then DE will go into an infinite loop.
115            for (int i = 0; i < input.getWidth(); i++) {
116                if (input.hasToken(i)) {
117                    if (((BooleanToken) input.get(i)).booleanValue()) {
118                        result = true;
119                    }
120                }
121            }
122
123            if (result) {
124                handleModelError(this, new InvariantViolationException(this,
125                        message.getExpression()));
126            }
127        }
128    }
129
130    /** Read one token from each input channel that has a token,
131     *  and if any token is true, invoke the model error handler.
132     *  @exception IllegalActionException If thrown by the parent class.
133     *  @return Whatever the base class returns (probably true).
134     */
135    @Override
136    public boolean postfire() throws IllegalActionException {
137        if (((BooleanToken) throwInPostfire.getToken()).booleanValue()) {
138            boolean result = false;
139
140            // NOTE: We need to consume data on all channels that have data.
141            // If we don't then DE will go into an infinite loop.
142            for (int i = 0; i < input.getWidth(); i++) {
143                if (input.hasToken(i)) {
144                    if (((BooleanToken) input.get(i)).booleanValue()) {
145                        result = true;
146                    }
147                }
148            }
149
150            if (result) {
151                handleModelError(this, new InvariantViolationException(this,
152                        message.getExpression()));
153            }
154        }
155        return super.postfire();
156    }
157}