001/* A Branch transfers tokens through a channel that crosses a composite
002 actor boundary.
003
004 Copyright (c) 1998-2014 The Regents of the University of California.
005 All rights reserved.
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the above
009 copyright notice and the following two paragraphs appear in all copies
010 of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION_2
026 COPYRIGHTENDKEY
027
028
029 */
030package ptolemy.actor.process;
031
032import ptolemy.data.Token;
033import ptolemy.kernel.util.IllegalActionException;
034import ptolemy.kernel.util.InternalErrorException;
035import ptolemy.kernel.util.Nameable;
036
037///////////////////////////////////////////////////////////////////
038//// Branch
039
040/**
041 A Branch transfers tokens through a channel that crosses a composite
042 actor boundary. Branch implements the Runnable class and the execution
043 of a branch object is controlled by an instantiation of the
044 BranchController class. Each branch object is assigned two receiver
045 objects and each of these receiver objects must implement the
046 ProcessReceiver class. One of the assigned receivers is referred to as
047 the producer receiver (the channel source) and the other is referred to
048 as the consumer receiver (the channel destination).
049 <P>
050 During its execution a branch attempts to get data from the producer
051 receiver and put data in the consumer receiver. The communication
052 semantics of the producer receiver get() method are dependent upon the
053 model of computation associated with the producer receiver. In cases
054 where a blocking read occurs, the producer receiver registers the block
055 with the calling branch leading to a blocked branch. So that the producer
056 receiver knows which branch to register the block with, a branch always
057 invokes the receiver's get() method by passing itself as an argument.
058 A blocked branch registers the block with the branch controller that it
059 is assigned to.
060 <P>
061 Putting data in a consumer receiver is symmetrically analogous to getting
062 data from a producer receiver. In cases where a blocking write occurs,
063 the consumer receiver registers the block with the calling branch leading
064 to a blocked branch. So that the consumer receiver knows which branch to
065 register the block with, a branch always invokes the receiver's put()
066 method by passing itself as an argument.
067
068 @author John S. Davis II
069 @version $Id$
070 @since Ptolemy II 1.0
071 @Pt.ProposedRating Red (davisj)
072 @Pt.AcceptedRating Red (davisj)
073 */
074public class Branch implements Runnable {
075    /** Construct a branch object with a branch controller.
076     *
077     *  @param controller The branch controller assigned to this branch.
078     *  @exception IllegalActionException Not thrown in this base class.
079     *  @deprecated Use this constructor for testing purposes only.
080     */
081    @Deprecated
082    public Branch(BranchController controller) throws IllegalActionException {
083        _controller = controller;
084    }
085
086    /** Construct a branch object with a producer receiver, a consumer
087     *  receiver and a branch controller.
088     *
089     *  @param producerReceiver The producer receiver assigned to this branch.
090     *  @param consumerReceiver The consumer receiver assigned to this branch.
091     *  @param controller The branch controller assigned to this branch.
092     *  @exception IllegalActionException If the receivers assigned to
093     *   this branch are null or improperly configured.
094     */
095    public Branch(ProcessReceiver producerReceiver,
096            ProcessReceiver consumerReceiver, BranchController controller)
097            throws IllegalActionException {
098        _controller = controller;
099
100        if (producerReceiver == null || consumerReceiver == null) {
101            throw new IllegalActionException(
102                    "The boundary " + "receivers of this branch are null.");
103        }
104
105        if (!producerReceiver.isProducerReceiver()) {
106            String name = ((Nameable) consumerReceiver.getContainer())
107                    .getFullName();
108            throw new IllegalActionException("Receiver in the port: " + name
109                    + " is not a producer receiver");
110        }
111
112        _producerReceiver = producerReceiver;
113
114        if (!consumerReceiver.isConsumerReceiver()) {
115            String name = ((Nameable) consumerReceiver.getContainer())
116                    .getFullName();
117            throw new IllegalActionException("Receiver in the port: " + name
118                    + " is not a consumer receiver");
119        }
120
121        _consumerReceiver = consumerReceiver;
122    }
123
124    ///////////////////////////////////////////////////////////////////
125    ////                         public methods                    ////
126
127    /** Return the consumer receiver that this branch puts data into.
128     *
129     *  @return The consumer receiver that this branch puts data into.
130     *  @see ptolemy.actor.process.BoundaryDetector
131     */
132    public ProcessReceiver getConsumerReceiver() {
133        return _consumerReceiver;
134    }
135
136    /** Return the producer receiver that this branch gets data from.
137     *
138     * @return The producer receiver that this branch gets data from.
139     * @see ptolemy.actor.process.BoundaryDetector
140     */
141    public ProcessReceiver getProducerReceiver() {
142        return _producerReceiver;
143    }
144
145    /** Return true if this branch is active.
146     *
147     *  @return True if this branch is still alive.
148     */
149    public boolean isActive() {
150        return _active;
151    }
152
153    /** Repeatedly transfer a single token between the producer
154     *  receiver and the consumer receiver as long as the branch
155     *  is active or until a TerminateProcessException is thrown.
156     */
157    @Override
158    public void run() {
159        try {
160            setActive(true);
161
162            while (isActive()) {
163                transferToken();
164            }
165        } catch (IllegalActionException exception) {
166            // FIXME: Is this the right thing to do?
167            throw new InternalErrorException(exception);
168        } finally {
169            _controller._getDirector().removeThread(Thread.currentThread());
170        }
171    }
172
173    /** Set a flag indicating this branch is no longer active.
174     *
175     *  @param value A boolean indicating whether this branch is
176     *   still active.
177     */
178    public void setActive(boolean value) {
179        _active = value;
180    }
181
182    /** Transfer a single token from the producer receiver to the
183     *  consumer receiver. If either the producer receiver or
184     *  consumer receiver is null then return without attempting
185     *  token transfer.
186     *  @exception IllegalActionException If the token is not acceptable
187     *   to one of the ports (e.g., wrong type).
188     */
189    public void transferToken() throws IllegalActionException {
190        if (_producerReceiver == null) {
191            return;
192        } else if (_consumerReceiver == null) {
193            return;
194        }
195
196        Token token = _producerReceiver.get();
197        _consumerReceiver.put(token);
198    }
199
200    ///////////////////////////////////////////////////////////////////
201    ////                         private variables                 ////
202    private boolean _active = false;
203
204    private BranchController _controller;
205
206    private ProcessReceiver _producerReceiver;
207
208    private ProcessReceiver _consumerReceiver;
209}