001/*
002 * Copyright (c) 2005-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.sms;
031
032import java.util.Iterator;
033import java.util.Vector;
034
035import ptolemy.actor.IOPort;
036import ptolemy.actor.TypedIOPort;
037import ptolemy.data.type.BaseType;
038import ptolemy.data.type.RecordType;
039import ptolemy.data.type.Type;
040import ptolemy.kernel.util.IllegalActionException;
041import ptolemy.kernel.util.NameDuplicationException;
042import ptolemy.kernel.util.NamedObj;
043
044/**
045 * A compoiste port is a virtual port that encapsulates a set of underlying
046 * ports (both ptolemy ports and other virtual ports). A composite port (and
047 * virtual ports in general) can be annotated using semantic types. For example,
048 * given an actor with a 'lat' and 'lon' port, a port generalization 'pg' can be
049 * constructed that encapsulates both 'lat' and 'lon'; and a semantic type such
050 * as "Location" can be assigned to 'pg', stating that 'lat' and 'lon' values
051 * combined form a location value.
052 * <p>
053 * A compoiste port may <b>only</b> be contained within an entity (e.g., an
054 * actor). A virtual port must have a name.
055 * 
056 * @author Shawn Bowers
057 * @created June 16, 2005
058 */
059
060public class KeplerCompositeIOPort extends KeplerVirtualIOPort {
061
062        /**
063         * Constructor
064         * 
065         * @param container
066         *            Description of the Parameter
067         * @param name
068         *            The value of the property
069         * @exception IllegalActionException
070         *                Description of the Exception
071         * @exception NameDuplicationException
072         *                Description of the Exception
073         */
074        public KeplerCompositeIOPort(NamedObj container, String name)
075                        throws IllegalActionException, NameDuplicationException {
076                super(container, name);
077                if (name == null) {
078                        String msg = "Port generalization must have a non-null name";
079                        throw new IllegalActionException(this, msg);
080                }
081        }
082
083        public void setName(String name) throws IllegalActionException,
084                        NameDuplicationException {
085                if (name == null) {
086                        String msg = "Port generalization must have a non-null name";
087                        throw new IllegalActionException(this, msg);
088                }
089                super.setName(name);
090        }
091
092        /**
093         * @return The list of encapsulated port references for this port
094         *         generalization. Each returned reference can be called to obtain
095         *         the actual port.
096         */
097        public Vector getEncapsulatedPortReferences() {
098                return new Vector(attributeList(KeplerIOPortReference.class));
099        }
100
101        /**
102         * Assigns the given ptolemy port reference to the current set of
103         * encapsulated ports. Creates a new reference for the port and adds to the
104         * generalization.
105         * 
106         * @param port
107         *            The ptolemy port to encapsulate.
108         */
109        public void addEncapsulatedPort(IOPort port) throws IllegalActionException,
110                        NameDuplicationException {
111                _addPort(port);
112        }
113
114        /**
115         * Assigns the given virtual port to the current set of encapsulated ports.
116         * This operation creates a reference to the given port.
117         * 
118         * @param vport
119         *            The virtual port to encapsulate.
120         */
121        public void addEncapsulatedPort(KeplerVirtualIOPort port)
122                        throws IllegalActionException, NameDuplicationException {
123                _addPort(port);
124        }
125
126        /**
127     * 
128     */
129        private void _addPort(Object obj) throws IllegalActionException,
130                        NameDuplicationException {
131                // adding a ptolemy port
132                if (obj instanceof IOPort) {
133                        IOPort port = (IOPort) obj;
134                        // make sure the port has the same direction
135                        if (!_validDirection(port)) {
136                                String msg = "error adding port '" + port.getName()
137                                                + "' to port generalization '" + getName()
138                                                + "': mismatched input/output directions";
139                                throw new IllegalActionException(this, msg);
140                        }
141                        String refname = "_" + port.getName() + "_ref";
142                        KeplerIOPortReference portRef = new KeplerIOPortReference(this,
143                                        refname);
144                        portRef.setPort(port);
145                }
146                // adding a kepler virtual port
147                else if (obj instanceof KeplerVirtualIOPort) {
148                        KeplerVirtualIOPort port = (KeplerVirtualIOPort) obj;
149                        // make sure the port has the same direction
150                        if (!_validDirection(port)) {
151                                String msg = "error adding port '" + port.getName()
152                                                + "' to port generalization '" + getName()
153                                                + "': mismatched input/output directions";
154                                throw new IllegalActionException(this, msg);
155                        }
156                        String refname = "_" + port.getName() + "_ref";
157                        KeplerVirtualIOPortReference portRef = new KeplerVirtualIOPortReference(
158                                        this, refname);
159                        portRef.setPort(port);
160                }
161
162        }
163
164        /**
165     * 
166     */
167        private boolean _validDirection(IOPort port) {
168                if (_direction == null) {
169                        _direction = port.isOutput() ? _OUTPUT : _INPUT;
170                        return true;
171                }
172
173                if (port.isOutput() && _direction.equals(_INPUT))
174                        return false;
175                else if (port.isInput() && _direction.equals(_OUTPUT))
176                        return false;
177
178                return true;
179        }
180
181        /**
182     * 
183     */
184        private boolean _validDirection(KeplerVirtualIOPort port) {
185                if (_direction == null) {
186                        _direction = port.isOutput() ? _OUTPUT : _INPUT;
187                        return true;
188                }
189
190                // get the virtual port direction
191                if (port.isOutput() && _direction.equals(_INPUT))
192                        return false;
193                else if (port.isInput() && _direction.equals(_OUTPUT))
194                        return false;
195
196                return true;
197        }
198
199        /**
200     * 
201     */
202        public boolean isOutput() {
203                return _OUTPUT.equals(_direction);
204        }
205
206        /**
207     * 
208     */
209        public boolean isInput() {
210                return _INPUT.equals(_direction);
211        }
212
213        /**
214         * Returns a record type of the encapsulated ports, where the labels are the
215         * port names.
216         */
217        public Type getType() {
218                Vector<String> labels = new Vector<String>();
219                Vector<Type> types = new Vector<Type>();
220                // get all the ports and add their names and types
221                for (Iterator iter = getEncapsulatedPortReferences().iterator(); iter
222                                .hasNext();) {
223                        Object ref = iter.next();
224                        // it should be a port reference
225                        if (ref instanceof KeplerIOPortReference) {
226                                Object obj = ((KeplerIOPortReference) ref).getPort();
227                                // it has a type
228                                if (obj instanceof TypedIOPort) {
229                                        TypedIOPort port = (TypedIOPort) obj;
230                                        String label = port.getName();
231                                        labels.add(label);
232                                        Type type = port.getType() == null ? BaseType.UNKNOWN
233                                                        : port.getType();
234                                        types.add(type);
235                                }
236                                // it doesn't have a type, use unknown type
237                                else if (obj instanceof IOPort) {
238                                        IOPort port = (IOPort) obj;
239                                        String label = port.getName();
240                                        labels.add(label);
241                                        types.add(BaseType.UNKNOWN);
242                                }
243                                // it is a virtual port
244                                else if (obj instanceof KeplerVirtualIOPort) {
245                                        KeplerVirtualIOPort port = (KeplerVirtualIOPort) obj;
246                                        String label = port.getName();
247                                        labels.add(label);
248                                        Type type = port.getType() == null ? BaseType.UNKNOWN
249                                                        : port.getType();
250                                        types.add(type);
251                                }
252                        }
253                }
254
255                String[] recLabels = new String[labels.size()];
256                Type[] recTypes = new Type[types.size()];
257                int i = 0;
258                for (Iterator<String> iter = labels.iterator(); iter.hasNext(); i++)
259                        recLabels[i] = iter.next();
260                i = 0;
261                for (Iterator<Type> iter = types.iterator(); iter.hasNext(); i++)
262                        recTypes[i] = iter.next();
263                return new RecordType(recLabels, recTypes);
264        }
265
266        /**
267     *
268     */
269        public String toString() {
270                return getName();
271        }
272
273        /** private members */
274
275        private String _direction = null;
276        private String _OUTPUT = "output";
277        private String _INPUT = "input";
278
279} // KeplerCompositeIOPort