001/* A port that updates a parameter of the container.
002
003 Copyright (c) 2001-2015 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 */
027package ptolemy.actor.parameters;
028
029import ptolemy.actor.TypedIOPort;
030import ptolemy.data.IntToken;
031import ptolemy.data.expr.Parameter;
032import ptolemy.kernel.ComponentEntity;
033import ptolemy.kernel.Entity;
034import ptolemy.kernel.util.Attribute;
035import ptolemy.kernel.util.IllegalActionException;
036import ptolemy.kernel.util.KernelException;
037import ptolemy.kernel.util.NameDuplicationException;
038import ptolemy.kernel.util.NamedObj;
039import ptolemy.kernel.util.Settable;
040import ptolemy.kernel.util.Workspace;
041
042///////////////////////////////////////////////////////////////////
043//// ParameterPort
044
045/**
046 A specialized port for use with PortParameter.  This port is created
047 by an instance of PortParameter and provides values to a parameter.
048 Data should not be read directly from this port.  Instead, the update
049 method of the corresponding PortParameter should be invoked.  This
050 port is only useful if the container is opaque, however, this is not
051 checked.
052
053 @see PortParameter
054 @author  Edward A. Lee
055 @version $Id$
056 @since Ptolemy II 3.0
057 @Pt.ProposedRating Green (eal)
058 @Pt.AcceptedRating Yellow (neuendor)
059 */
060public class ParameterPort extends TypedIOPort {
061    /** Construct a new input port in the specified container with the
062     *  specified name. The specified container
063     *  must implement the Actor interface, or an exception will be thrown.
064     *  @param container The container.
065     *  @param name The name of the port.
066     *  @exception IllegalActionException If the port is not of an acceptable
067     *   class for the container, or if the container does not implement the
068     *   Actor interface.
069     *  @exception NameDuplicationException If the name coincides with
070     *   a port already in the container.
071     */
072    public ParameterPort(ComponentEntity container, String name)
073            throws IllegalActionException, NameDuplicationException {
074        this(container, name, null);
075    }
076
077    /** Construct a new input port in the specified container with the
078     *  specified name. The specified container
079     *  must implement the Actor interface, or an exception will be thrown.
080     *  @param container The container.
081     *  @param name The name of the port.
082     *  @param parameter The associate PortParameter, or null to create one.
083     *  @exception IllegalActionException If the port is not of an acceptable
084     *   class for the container, or if the container does not implement the
085     *   Actor interface.
086     *  @exception NameDuplicationException If the name coincides with
087     *   a port already in the container.
088     */
089    protected ParameterPort(ComponentEntity container, String name,
090            PortParameter parameter)
091            throws IllegalActionException, NameDuplicationException {
092        super(container, name);
093        setInput(true);
094        setMultiport(false);
095        _parameter = parameter;
096
097        if (_parameter == null) {
098            // This is apparently being created directly, e.g. in MoML, rather than
099            // the preferred way of creating a PortParameter. Create or capture
100            // the corresponding PortParameter.
101            Attribute existingParameter = container.getAttribute(name);
102            if (existingParameter instanceof PortParameter) {
103                _parameter = (PortParameter) existingParameter;
104                _parameter._port = this;
105            } else {
106                _parameter = new PortParameter(container, name, this);
107            }
108        }
109        _setTypeConstraints();
110
111        // Declare to the SDF scheduler that this port consumes one
112        // token, despite not being connected on the inside.
113        Parameter tokenConsumptionRate = new Parameter(this,
114                "tokenConsumptionRate", new IntToken(1));
115        tokenConsumptionRate.setVisibility(Settable.NOT_EDITABLE);
116        tokenConsumptionRate.setPersistent(false);
117
118        Parameter notDraggable = new Parameter(this, "_notDraggable");
119        notDraggable.setPersistent(false);
120    }
121
122    ///////////////////////////////////////////////////////////////////
123    ////                         public methods                    ////
124
125    /** Clone the port. This overrides the base class to remove
126     *  the current association with a parameter.  It is assumed that the
127     *  parameter will also be cloned, and when the containers are set of
128     *  this port and that parameter, whichever one is set second
129     *  will result in re-establishment of the association.
130     *  @param workspace The workspace in which to place the cloned port.
131     *  @exception CloneNotSupportedException Not thrown in this base class.
132     *  @see java.lang.Object#clone()
133     *  @return The cloned port.
134     */
135    @Override
136    public Object clone(Workspace workspace) throws CloneNotSupportedException {
137        ParameterPort newObject = (ParameterPort) super.clone(workspace);
138
139        // Cannot establish an association with the cloned parameter until
140        // that parameter is cloned and the container of both is set.
141        newObject._parameter = null;
142        return newObject;
143    }
144
145    /** Get the associated parameter.
146     *  @return The associated parameter.
147     */
148    public PortParameter getParameter() {
149        if (_parameter == null) {
150            // Attempt to find the parameter.
151            NamedObj container = getContainer();
152            if (container != null) {
153                Attribute candidate = container.getAttribute(getName());
154                if (candidate instanceof PortParameter) {
155                    _parameter = (PortParameter) candidate;
156                    _setTypeConstraints();
157                }
158            }
159        }
160        return _parameter;
161    }
162
163    /** Set the container of this port. If the container is different
164     *  from what it was before and there is an associated parameter, then
165     *  also change the container of the parameter.
166     *  @see PortParameter
167     *  @param entity The new container.
168     *  @exception IllegalActionException If the superclass throws it.
169     *  @exception NameDuplicationException If the superclass throws it.
170     */
171    @Override
172    public void setContainer(Entity entity)
173            throws IllegalActionException, NameDuplicationException {
174        if (_settingContainer) {
175            // Recursive call through the parameter.
176            return;
177        }
178        Entity previousContainer = (Entity) getContainer();
179        if (previousContainer == entity) {
180            // No change.
181            return;
182        }
183        super.setContainer(entity);
184
185        // If there is an associated parameter, and the container has changed,
186        // change that container too.
187        if (_parameter != null) {
188            try {
189                _settingContainer = true;
190                _parameter.setContainer(entity);
191            } catch (KernelException ex) {
192                super.setContainer(previousContainer);
193                throw ex;
194            } finally {
195                _settingContainer = false;
196            }
197        }
198        if (previousContainer == null) {
199            // This may be part of cloning operation, in which case we need to
200            // establish type constraints that are present in the original.
201            // Since ports are normally cloned after parameters, the container should
202            // have the relevant parameter by now.
203            if (getParameter() != null) {
204                _setTypeConstraints();
205            }
206        }
207    }
208
209    /** Set the display name, and propagate the name change to the
210     *  associated parameter.
211     *  Increment the version of the workspace.
212     *  This method is write-synchronized on the workspace.
213     *  @param name The new display name..
214     */
215    @Override
216    public void setDisplayName(String name) {
217        if (_settingName) {
218            return;
219        }
220        super.setDisplayName(name);
221        PortParameter parameter = getParameter();
222        if (parameter != null) {
223            try {
224                _settingName = true;
225                parameter.setDisplayName(name);
226            } finally {
227                _settingName = false;
228            }
229        }
230    }
231
232    /** Set the name, and propagate the name change to the
233     *  associated parameter.  If a null argument is given, then the
234     *  name is set to an empty string.
235     *  Increment the version of the workspace.
236     *  This method is write-synchronized on the workspace.
237     *  @param name The new name.
238     *  @exception IllegalActionException If the name contains a period.
239     *  @exception NameDuplicationException If the container already
240     *   contains an attribute with the proposed name.
241     */
242    @Override
243    public void setName(String name)
244            throws IllegalActionException, NameDuplicationException {
245        if (_settingName) {
246            return;
247        }
248        super.setName(name);
249        PortParameter parameter = getParameter();
250        if (parameter != null) {
251            String oldName = getName();
252            try {
253                _settingName = true;
254                parameter.setName(name);
255            } catch (KernelException ex) {
256                super.setName(oldName);
257                throw ex;
258            } finally {
259                _settingName = false;
260            }
261        }
262    }
263
264    ///////////////////////////////////////////////////////////////////
265    ////                         protected methods                 ////
266
267    /** Set the type constraints between the protected member _parameter
268     *  and this port.  This is a protected method so that subclasses
269     *  can define different type constraints.  It is assured that when
270     *  this is called, _parameter is non-null.  However, use caution,
271     *  since this method may be called during construction of this
272     *  port, and hence the port may not be fully constructed.
273     */
274    protected void _setTypeConstraints() {
275        PortParameter parameter = getParameter();
276        if (parameter != null) {
277            parameter.setTypeSameAs(this);
278        }
279    }
280
281    ///////////////////////////////////////////////////////////////////
282    ////                       protected members                   ////
283
284    /** The associated parameter. */
285    protected PortParameter _parameter;
286
287    ///////////////////////////////////////////////////////////////////
288    ////                         private members                   ////
289
290    /** Indicator that we are in the midst of setting the container. */
291    private boolean _settingContainer = false;
292
293    /** Indicator that we are in the midst of setting the name. */
294    private boolean _settingName = false;
295}