001/* A port for use in component domains.
002
003 Copyright (c) 2003-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.component;
029
030import java.util.Iterator;
031
032import ptolemy.data.TupleToken;
033import ptolemy.kernel.ComponentEntity;
034import ptolemy.kernel.ComponentPort;
035import ptolemy.kernel.util.CrossRefList;
036import ptolemy.kernel.util.IllegalActionException;
037import ptolemy.kernel.util.NameDuplicationException;
038import ptolemy.kernel.util.Workspace;
039
040///////////////////////////////////////////////////////////////////
041//// MethodCallPort
042
043/**
044 A port for use in the component domain.
045
046 @author Yang Zhao
047 @version $Id$
048 @since Ptolemy II 11.0
049 @Pt.ProposedRating yellow(cxh)
050 @Pt.AcceptedRating red(cxh)
051 */
052public class MethodCallPort extends ComponentPort {
053    /** Construct a port in the default workspace with an empty string
054     *  as its name. Increment the version number of the workspace.
055     *  The object is added to the workspace directory.
056     */
057    public MethodCallPort() {
058        super();
059    }
060
061    /** Construct a port in the specified workspace with an empty
062     *  string as a name. You can then change the name with setName().
063     *  If the workspace argument is null, then use the default workspace.
064     *  The object is added to the workspace directory.
065     *  Increment the version number of the workspace.
066     *  @param workspace The workspace that will list the port.
067     */
068    public MethodCallPort(Workspace workspace) {
069        super(workspace);
070    }
071
072    /** Construct a port with the given name contained by the specified
073     *  entity. The container argument must not be null, or a
074     *  NullPointerException will be thrown.  This port will use the
075     *  workspace of the container for synchronization and version counts.
076     *  If the name argument is null, then the name is set to the empty
077     *  string.  Increment the version of the workspace.
078     *  @param container The container entity.
079     *  @param name The name of the port.
080     *  @exception IllegalActionException If the port is not of an acceptable
081     *   class for the container.
082     *  @exception NameDuplicationException If the name coincides with
083     *   a port already in the container.
084     */
085    public MethodCallPort(ComponentEntity container, String name)
086            throws IllegalActionException, NameDuplicationException {
087        super(container, name);
088    }
089
090    /** Construct an IOPort with a container and a name that is
091     *  either an input, an output, or both, depending on the third
092     *  and fourth arguments. The specified container must implement
093     *  the Actor interface or an exception will be thrown.
094     *
095     *  @param container The container actor.
096     *  @param name The name of the port.
097     *  @param isProvidedPort True if this port provides the method.
098     *  @exception IllegalActionException If the port is not of an acceptable
099     *   class for the container, or if the container does not implement the
100     *   Actor interface.
101     *  @exception NameDuplicationException If the name coincides with
102     *   a port already in the container.
103     */
104    public MethodCallPort(ComponentEntity container, String name,
105            boolean isProvidedPort)
106            throws IllegalActionException, NameDuplicationException {
107        this(container, name);
108        _isProvider = isProvidedPort;
109    }
110
111    ///////////////////////////////////////////////////////////////////
112    ////                         public methods                    ////
113
114    /** Clone the object into the specified workspace. The new object is
115     *  <i>not</i> added to the directory of that workspace (you must do this
116     *  yourself if you want it there).
117     *  The result is a new port with no connections and no container.
118     *  @param workspace The workspace for the cloned object.
119     *  @exception CloneNotSupportedException If one or more of the
120     *   attributes cannot be cloned.
121     *  @return A new ComponentPort.
122     */
123    @Override
124    public Object clone(Workspace workspace) throws CloneNotSupportedException {
125        MethodCallPort newObject = (MethodCallPort) super.clone(workspace);
126        newObject._insideLinks = new CrossRefList(newObject);
127        return newObject;
128    }
129
130    ///////////////////////////////////////////////////////////////////
131    ////                         public methods                    ////
132
133    /** Call the method associated with this port with the specified
134     *  arguments.
135     *  <p>
136     *  If this port is a provider, as indicated by @link{#isProvider()},
137     *  then this method returns TupleToken.VOID, an empty tuple token.
138     *  Subclasses should override this method to perform whatever
139     *  functionality is associated with this method.
140     *  <p>
141     *  If this port is not a provider of this method, then this method
142     *  delegates the call to all ports to which this port is
143     *  deeply connected that are providers.  The order in which those
144     *  calls are performed is determined by the order in which connections
145     *  are made. The returned token is a concatenation of the returned
146     *  values of all the called methods. If there is nothing connected,
147     *  then this method will return TupleToken.VOID.
148     *  @param arguments The arguments to the method.
149     *  @see #isProvider()
150     *  @see ptolemy.data.TupleToken#VOID
151     */
152    public synchronized TupleToken call(TupleToken arguments) {
153        if (!isProvider()) {
154            Iterator ports = this.deepConnectedPortList().iterator();
155            TupleToken result = TupleToken.VOID;
156
157            while (ports.hasNext()) {
158                MethodCallPort port = (MethodCallPort) ports.next();
159
160                if (port.isProvider()) {
161                    result = TupleToken.merge(result, port.call(arguments));
162                }
163            }
164
165            return result;
166        }
167
168        // The port provided should over write this method.
169        return TupleToken.VOID;
170    }
171
172    /** Return true if this port provides the method,
173     *  vs. requires the method.  By default, this method returns
174     *  false, meaning that the port requires rather than provides
175     *  the method.
176     *  @see #setProvider(boolean)
177     *  @see #MethodCallPort(ComponentEntity, String, boolean)
178     *  @see #call(TupleToken)
179     *  @return True if this port provides the method.
180     */
181    public boolean isProvider() {
182        return _isProvider;
183    }
184
185    /** Call with argument true to specify that this port provides the method,
186     *  and call with argument false to specify that it requires the method.
187     *  @see #isProvider()
188     *  @see #MethodCallPort(ComponentEntity, String, boolean)
189     *  @see #call(TupleToken)
190     */
191    public void setProvider(boolean isProvider) {
192        _isProvider = isProvider;
193    }
194
195    ///////////////////////////////////////////////////////////////////
196    ////                         private variables                 ////
197
198    /** Indicator of whether this port provides the method. */
199    private boolean _isProvider = false;
200}