001/* Composite actor with multiple refinements.
002
003 Copyright (c) 2006-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 */
027package ptolemy.actor.lib.hoc;
028
029import java.util.Iterator;
030import java.util.Set;
031
032import ptolemy.actor.IOPort;
033import ptolemy.actor.TypedCompositeActor;
034import ptolemy.kernel.CompositeEntity;
035import ptolemy.kernel.Port;
036import ptolemy.kernel.util.IllegalActionException;
037import ptolemy.kernel.util.InternalErrorException;
038import ptolemy.kernel.util.NameDuplicationException;
039import ptolemy.kernel.util.Workspace;
040
041///////////////////////////////////////////////////////////////////
042//// MultiCompositeActor
043
044/**
045 A composite actor that can have several refinements.
046
047 @see Refinement
048 @author Edward A. Lee
049 @version $Id$
050 @since Ptolemy II 5.2
051 @Pt.ProposedRating Red (eal)
052 @Pt.AcceptedRating Red (reviewmoderator)
053 */
054public class MultiCompositeActor extends TypedCompositeActor {
055    /** Construct a composite actor in the specified workspace with
056     *  no container and an empty string as a name. You can then change
057     *  the name with setName(). If the workspace argument is null, then
058     *  use the default workspace.
059     *  @param workspace The workspace that will list the actor.
060     *  @exception IllegalActionException If the name has a period in it, or
061     *   the director is not compatible with the specified container.
062     *  @exception NameDuplicationException If the container already contains
063     *   an entity with the specified name.
064     */
065    public MultiCompositeActor(Workspace workspace)
066            throws IllegalActionException, NameDuplicationException {
067        super(workspace);
068        _init();
069    }
070
071    /** Construct a composite actor with a name and a container.
072     *  The container argument must not be null, or a
073     *  NullPointerException will be thrown.
074     *  @param container The container.
075     *  @param name The name of this actor.
076     *  @exception IllegalActionException If the container is incompatible
077     *   with this actor.
078     *  @exception NameDuplicationException If the name coincides with
079     *   an actor already in the container.
080     */
081    public MultiCompositeActor(CompositeEntity container, String name)
082            throws IllegalActionException, NameDuplicationException {
083        super(container, name);
084        _init();
085    }
086
087    ///////////////////////////////////////////////////////////////////
088    ////                         public methods                    ////
089
090    /** Mirror a set of container ports in the refinement.
091     *  @param refinement The refinement in which to create ports.
092     *  @param portsToMirror The ports to mirror in the refinement.
093     *  @exception IllegalActionException If the port cannot be set
094     *  to a multiport or to an output.
095     *  @exception NameDuplicationException If a port cannot be added
096     *  to the the refinement.
097     */
098    public static void mirrorContainerPortsInRefinement(Refinement refinement,
099            Set<Port> portsToMirror)
100            throws IllegalActionException, NameDuplicationException {
101
102        for (Port port : portsToMirror) {
103            try {
104                refinement.setMirrorDisable(true);
105                Port newPort = refinement.newPort(port.getName());
106                if (newPort instanceof RefinementPort
107                        && port instanceof IOPort) {
108                    try {
109                        ((RefinementPort) newPort).setMirrorDisable(true);
110
111                        if (((IOPort) port).isInput()) {
112                            ((RefinementPort) newPort).setInput(true);
113                        }
114
115                        if (((IOPort) port).isOutput()) {
116                            ((RefinementPort) newPort).setOutput(true);
117                        }
118
119                        if (((IOPort) port).isMultiport()) {
120                            ((RefinementPort) newPort).setMultiport(true);
121                        }
122                    } finally {
123                        ((RefinementPort) newPort).setMirrorDisable(false);
124                    }
125                }
126            } finally {
127                refinement.setMirrorDisable(false);
128            }
129        }
130    }
131
132    /** Create a new port with the specified name in this entity
133     *  and all the refinements.  Link these ports so that
134     *  if the new port is set to be an input, output, or multiport, then
135     *  the change is mirrored in the other ports.  The new port will be
136     *  an instance of MultiCompositePort, which extends TypedIOPort.
137     *  This method is write-synchronized on the workspace, and increments
138     *  its version number.
139     *  @param name The name to assign to the newly created port.
140     *  @return The new port.
141     *  @exception NameDuplicationException If the entity already has a port
142     *   with the specified name.
143     */
144    @Override
145    public Port newPort(String name) throws NameDuplicationException {
146        try {
147            _workspace.getWriteAccess();
148
149            MultiCompositePort port = new MultiCompositePort(this, name);
150
151            // Create mirror ports.
152            Iterator entities = entityList(Refinement.class).iterator();
153            while (entities.hasNext()) {
154                Refinement entity = (Refinement) entities.next();
155                if (entity.getPort(name) == null) {
156                    try {
157                        entity._mirrorDisable = true;
158                        entity.newPort(name);
159                    } finally {
160                        entity._mirrorDisable = false;
161                    }
162                }
163            }
164            return port;
165        } catch (IllegalActionException ex) {
166            // This exception should not occur, so we throw a runtime
167            // exception.
168            throw new InternalErrorException(
169                    "MultiCompositeActor.newPort(): Internal error: "
170                            + ex.getMessage());
171        } finally {
172            _workspace.doneWriting();
173        }
174    }
175
176    ///////////////////////////////////////////////////////////////////
177    ////                         private methods                   ////
178
179    /** Initialize the model. */
180    private void _init() {
181        // The base class identifies the class name as TypedCompositeActor
182        // irrespective of the actual class name.  We override that here.
183        setClassName("ptolemy.actor.lib.hoc.MultiCompositeActor");
184
185    }
186}