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}