001/* A Token holder with a capacity of one 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.domains.modal.kernel;
029
030import java.util.LinkedList;
031import java.util.List;
032
033import ptolemy.actor.AbstractReceiver;
034import ptolemy.actor.IOPort;
035import ptolemy.actor.NoRoomException;
036import ptolemy.actor.NoTokenException;
037import ptolemy.data.Token;
038import ptolemy.kernel.util.IllegalActionException;
039import ptolemy.kernel.util.InternalErrorException;
040
041///////////////////////////////////////////////////////////////////
042//// FSMReceiver
043
044/**
045 A receiver with capacity one for which one can explicitly set the status.
046
047 @author Edward A. Lee
048 @version $Id$
049 @since Ptolemy II 8.0
050 @Pt.ProposedRating Yellow (eal)
051 @Pt.AcceptedRating Red (cxh)
052 */
053public class FSMReceiver extends AbstractReceiver {
054
055    /** Construct an empty receiver with no container.
056     *  The initial status is unknown.
057     */
058    public FSMReceiver() {
059        super();
060    }
061
062    /** Construct an empty receiver with the specified container.
063     *  The initial status is unknown.
064     *  @param container The container.
065     *  @exception IllegalActionException If the container does
066     *   not accept this receiver.
067     */
068    public FSMReceiver(IOPort container) throws IllegalActionException {
069        super(container);
070    }
071
072    ///////////////////////////////////////////////////////////////////
073    ////                         public methods                    ////
074
075    /** Clear this receiver of any contained token and set the known
076     *  status to true.
077     */
078    @Override
079    public void clear() {
080        _token = null;
081        _isKnown = true;
082    }
083
084    /** Return a list with the token currently in the receiver, or
085     *  an empty list if there is no such token.
086     *  @return A list of instances of Token.
087     *  @exception IllegalActionException If the status is unknown.
088     */
089    @Override
090    public List<Token> elementList() throws IllegalActionException {
091        if (!_isKnown) {
092            throw new IllegalActionException(getContainer(),
093                    "Receiver status is unknown.");
094        }
095        List<Token> result = new LinkedList<Token>();
096        if (_token != null) {
097            result.add(_token);
098        }
099        return result;
100    }
101
102    /** Get the contained Token.  If there is none, throw an exception.
103     *  The token is not removed. It can be repeatedly read.
104     *  @return The token contained by this receiver.
105     *  @exception NoTokenException If this receiver is empty or unknown
106     */
107    @Override
108    public Token get() throws NoTokenException {
109        if (_token == null) {
110            throw new NoTokenException(getContainer(),
111                    "Attempt to get data from an empty recever.");
112        }
113        if (!_isKnown) {
114            throw new NoTokenException(getContainer(),
115                    "Receiver status is unknown.");
116        }
117        return _token;
118    }
119
120    /** If the argument is 1, there is a token, and the status is known,
121     *  then return an array containing the one token. Otherwise, throw
122     *  an exception.
123     *  @exception NoTokenException If the status is unknown, if there is
124     *   no token, or if the argument is not 1.
125     */
126    @Override
127    public Token[] getArray(int numberOfTokens) throws NoTokenException {
128        if (!_isKnown) {
129            throw new NoTokenException(getContainer(),
130                    "Receiver status is unknown.");
131        }
132        if (numberOfTokens <= 0) {
133            throw new IllegalArgumentException(
134                    "Illegal argument to getArray():" + numberOfTokens);
135        }
136        if (numberOfTokens > 1) {
137            throw new NoTokenException(getContainer(),
138                    "Receiver can only contain one token, but request is for "
139                            + numberOfTokens);
140        }
141        if (_token == null) {
142            throw new NoTokenException(getContainer(), "Receiver is empty.");
143        }
144        // Check whether we need allocate the cached token array.
145        if (_tokenCache == null) {
146            _tokenCache = new Token[1];
147        }
148        _tokenCache[0] = _token;
149        return _tokenCache;
150    }
151
152    /** Return true.
153     *  @return True.
154     */
155    @Override
156    public boolean hasRoom() {
157        return true;
158    }
159
160    /** Return true if the argument is 1, and otherwise return false.
161     *  @param numberOfTokens The number of tokens to put into the receiver.
162     *  @return True if the argument is 1, and otherwise return false.
163     *  @exception IllegalArgumentException If the argument is not positive.
164     *   This is a runtime exception, so it does not need to be declared
165     *   explicitly.
166     */
167    @Override
168    public boolean hasRoom(int numberOfTokens) throws IllegalArgumentException {
169        if (numberOfTokens < 1) {
170            throw new IllegalArgumentException(
171                    "hasRoom() requires a positive argument.");
172        }
173        if (numberOfTokens > 1) {
174            return false;
175        }
176        return true;
177    }
178
179    /** Return true if this mailbox is not empty.
180     *  @return True if this mailbox is not empty.
181     *  @exception InternalErrorException If the status is not known.
182     */
183    @Override
184    public boolean hasToken() {
185        if (!_isKnown) {
186            throw new InternalErrorException(getContainer(), null,
187                    "Receiver status is not known.");
188        }
189        return _token != null;
190    }
191
192    /** Return true if the argument is 1 and this receiver is not empty,
193     *  and otherwise return false.
194     *  @param numberOfTokens The number of tokens to get from the receiver.
195     *  @return True if the argument is 1 and this receiver is not empty.
196     *  @exception InternalErrorException If the status is not known.
197     *  @exception IllegalArgumentException If the argument is not positive.
198     *   This is a runtime exception, so it does not need to be declared
199     *   explicitly.
200     */
201    @Override
202    public boolean hasToken(int numberOfTokens)
203            throws IllegalArgumentException {
204        if (!_isKnown) {
205            throw new InternalErrorException(getContainer(), null,
206                    "Receiver status is not known.");
207        }
208        if (numberOfTokens < 1) {
209            throw new IllegalArgumentException(
210                    "hasToken() requires a positive argument.");
211        }
212
213        if (numberOfTokens == 1) {
214            return _token != null;
215        }
216
217        return false;
218    }
219
220    /** Return whether the state of the receiver is known.
221     *  @return True if the state of the receiver is known.
222     *  @see #clear()
223     *  @see #put(Token)
224     */
225    @Override
226    public boolean isKnown() {
227        return _isKnown;
228    }
229
230    /** Put a token into this receiver.  If the argument is null, then the
231     *  receiver will not contain a token after this returns, getting the
232     *  same effect as calling clear(). If there was previously a token
233     *  in the receiver, this overwrites that token.
234     *  Set the known status of the receiver to true.
235     *  @param token The token to be put into the mailbox.
236     *  @exception NoRoomException If this mailbox is not empty.
237     */
238    @Override
239    public void put(Token token) throws NoRoomException {
240        _token = token;
241        _isKnown = true;
242    }
243
244    /** If the argument has one token, then put that token in
245     *  the receiver. Otherwise, throw an exception.
246     */
247    @Override
248    public void putArray(Token[] tokenArray, int numberOfTokens)
249            throws NoRoomException, IllegalActionException {
250        if (numberOfTokens != 1 || tokenArray.length < 1) {
251            throw new IllegalActionException(getContainer(),
252                    "Receiver cannot accept more than one token.");
253        }
254        put(tokenArray[0]);
255    }
256
257    /** Set the receiver to unknown. */
258    @Override
259    public void reset() throws IllegalActionException {
260        _isKnown = false;
261        _token = null;
262    }
263
264    ///////////////////////////////////////////////////////////////////
265    ////                         private variables                 ////
266
267    /** Flag indicating whether the state of the receiver is known. */
268    private boolean _isKnown = false;
269
270    /** The token held. */
271    private Token _token = null;
272
273    /** The cache used by the getArray() method to avoid reallocating. */
274    private Token[] _tokenCache;
275}