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.kernel.util.Attribute;
037import ptolemy.kernel.util.IllegalActionException;
038import ptolemy.kernel.util.NameDuplicationException;
039import ptolemy.kernel.util.NamedObj;
040import ptolemy.moml.MoMLChangeRequest;
041
042/**
043 * FIXME: Documentation ... A port generalization is a virtual port that
044 * encapsulates a set of underlying ports (both ptolemy ports and other virtual
045 * ports). A port generalization (and virtual ports in general) can be annotated
046 * using semantic types. For example, given an actor with a 'lat' and 'lon'
047 * port, a port generalization 'pg' can be constructed that encapsulates both
048 * 'lat' and 'lon'; and a semantic type such as "Location" can be assigned to
049 * 'pg', stating that 'lat' and 'lon' values combined form a location value.
050 * <p>
051 * A port generalization may <b>only</b> be contained within an entity (e.g., an
052 * actor). A virtual port must have a name.
053 * 
054 * @author Shawn Bowers
055 * @created June 20, 2005
056 */
057
058public class KeplerIOPortSemanticLink extends Attribute {
059
060        /**
061         * Constructor
062         * 
063         * @param container
064         *            Description of the Parameter
065         * @param name
066         *            The value of the property
067         * @exception IllegalActionException
068         *                Description of the Exception
069         * @exception NameDuplicationException
070         *                Description of the Exception
071         */
072        public KeplerIOPortSemanticLink(NamedObj container, String name)
073                        throws IllegalActionException, NameDuplicationException {
074                super(container, name);
075        }
076
077        /**
078         * FIXME: This should be "external" to the port ... Set the container of the
079         * link to the given container. This method fails, in addition to the normal
080         * ptolemy constraints for setting containers, if the given container is not
081         * a org.kepler.sms.KeplerVirtualIOPort or ptolemy IOPort object.
082         * 
083         * @param container
084         *            The container for this virtual port.
085         */
086        public void setContainer(NamedObj container) throws IllegalActionException,
087                        NameDuplicationException {
088                if (!(container instanceof IOPort || container instanceof KeplerVirtualIOPort)) {
089                        String msg = "Container not an IOPort or Kepler virtual IO port '"
090                                        + getName() + "'";
091                        throw new IllegalActionException(this, msg);
092                }
093                super.setContainer(container);
094        }
095
096        /**
097         * @return The domain of the link, which is an IOPort or
098         *         KeplerVirtualIOPort.
099         */
100        public Object getDomain() {
101                return getContainer();
102        }
103
104        /**
105         * Assigns the domain of this link. As a side effect, makes the domain the
106         * container for this object.
107         */
108        public void setDomain(IOPort domain) throws IllegalActionException,
109                        NameDuplicationException {
110                setContainer(domain);
111        }
112
113        /**
114         * Assigns the domain of this link. As a side effect, makes the domain the
115         * container for this object.
116         */
117        public void setDomain(KeplerVirtualIOPort domain)
118                        throws IllegalActionException, NameDuplicationException {
119                if (!_validateDomain(domain)) {
120                        String msg = "Domain port '" + domain.getName()
121                                        + "' does not match range" + " direction for link '"
122                                        + getName() + "'";
123                        throw new IllegalActionException(this, msg);
124                }
125                setContainer(domain);
126        }
127
128        /**
129         * @return The range of the link, which is an IOPort or KeplerVirtualIOPort
130         */
131        public Object getRange() {
132                KeplerIOPortReference ref = _getRangeRef();
133                if (ref != null)
134                        return ref.getPort();
135                return null;
136        }
137
138        /**
139         * @return The range as an IOPort reference. Null if there is no range.
140         */
141        private KeplerIOPortReference _getRangeRef() {
142                for (Iterator iter = attributeList().iterator(); iter.hasNext();) {
143                        Object obj = iter.next();
144                        if (obj instanceof KeplerIOPortReference)
145                                return (KeplerIOPortReference) obj;
146                }
147                return null;
148        }
149
150        /**
151         * Assigns the IOPort as the range of the link. Removes the current range if
152         * one exists.
153         */
154        public void setRange(IOPort range) throws IllegalActionException,
155                        NameDuplicationException {
156                if (range == null)
157                        return;
158                if (!_validateRange(range)) {
159                        String msg = "Range port '" + range.getName()
160                                        + "' does not match domain" + " direction for link '"
161                                        + getName() + "'";
162                        throw new IllegalActionException(this, msg);
163                }
164                KeplerIOPortReference ref = _getRangeRef();
165                if (ref != null) {
166                        MoMLChangeRequest request = new MoMLChangeRequest(this,
167                                        getContainer(), _swapRange(range));
168                        requestChange(request);
169                        System.out.println("HERE ... " + ref);
170                        System.out.println(exportMoML());
171                } else {
172                        ref = new KeplerIOPortReference(this, "_range");
173                        ((KeplerIOPortReference) ref).setPort(range);
174                }
175        }
176
177        /**
178         * Assigns the Virtual IOPort as the range of the link. Removes the current
179         * range if one exists.
180         */
181        public void setRange(KeplerVirtualIOPort range)
182                        throws IllegalActionException, NameDuplicationException {
183                if (range == null)
184                        return;
185                if (!_validateRange(range)) {
186                        String msg = "Range port '" + range.getName()
187                                        + "' does not match domain" + " direction for link '"
188                                        + getName() + "'";
189                        throw new IllegalActionException(this, msg);
190                }
191                KeplerIOPortReference ref = _getRangeRef();
192                if (ref != null) {
193                        MoMLChangeRequest request = new MoMLChangeRequest(this,
194                                        getContainer(), _swapRange(range));
195                        requestChange(request);
196                        System.out.println("HERE ... " + ref);
197                        System.out.println(exportMoML());
198                } else {
199                        ref = new KeplerVirtualIOPortReference(this, "_range");
200                        ((KeplerVirtualIOPortReference) ref).setPort(range);
201                }
202        }
203
204        /**
205         * Helper function to remove an attribute from an a link.
206         */
207        private String _swapRange(KeplerVirtualIOPort range) {
208                String linkStr = "";
209                if (getName() != null)
210                        linkStr += "<property name=\"" + getName() + "\" ";
211                else
212                        linkStr += "<property ";
213                linkStr += "class=\"" + this.getClass().getName() + "\">\n";
214                linkStr += "   <property name=\"_range\" ";
215                linkStr += "class=\"" + KeplerVirtualIOPortReference.class.getName()
216                                + "\" ";
217                linkStr += "value=\"" + range.getName() + "\"";
218                linkStr += "/>\n";
219
220                for (Iterator<SemanticProperty> iter = getSemanticProperties().iterator(); iter.hasNext();) {
221                        SemanticProperty p = iter.next();
222                        linkStr += "   " + p.exportMoML() + "\n";
223                }
224                return linkStr + "</property>";
225        }
226
227        /**
228         * Helper function to remove an attribute from an a link.
229         */
230        private String _swapRange(IOPort range) {
231                String linkStr = "";
232                if (getName() != null)
233                        linkStr += "<property name=\"" + getName() + "\" ";
234                else
235                        linkStr += "<property ";
236                linkStr += "class=\"" + this.getClass().getName() + "\">\n";
237                linkStr += "   <property name=\"_range\" ";
238                linkStr += "class=\"" + KeplerIOPortReference.class.getName() + "\" ";
239                linkStr += "value=\"" + range.getName() + "\"";
240                linkStr += "/>\n";
241
242                for (Iterator<SemanticProperty> iter = getSemanticProperties().iterator(); iter.hasNext();) {
243                        SemanticProperty p = iter.next();
244                        linkStr += "   " + p.exportMoML() + "\n";
245                }
246                return linkStr + "</property>";
247        }
248
249        /**
250     * 
251     */
252        public Vector<SemanticProperty> getSemanticProperties() {
253                Vector<SemanticProperty> result = new Vector<SemanticProperty>();
254                for (Iterator<SemanticProperty> iter = attributeList(SemanticProperty.class).iterator(); iter
255                                .hasNext();)
256                        result.add(iter.next());
257                return result;
258        }
259
260        /**
261     * 
262     */
263        public void addSemanticProperty(SemanticProperty property)
264                        throws IllegalActionException, NameDuplicationException {
265                property.setContainer(this);
266        }
267
268        /**
269         * @return True if the given domain direction matches existing range
270         *         direction.
271         */
272        private boolean _validateDomain(IOPort domain) {
273                if (getRange() != null) {
274                        Object obj = getRange();
275                        if (obj instanceof IOPort)
276                                return ((IOPort) obj).isOutput() == domain.isOutput();
277                        else if (obj instanceof KeplerVirtualIOPort)
278                                return ((KeplerVirtualIOPort) obj).isOutput() == domain
279                                                .isOutput();
280                }
281                return true;
282        }
283
284        /**
285         * @return True if the given domain direction matches existing range
286         *         direction.
287         */
288        private boolean _validateDomain(KeplerVirtualIOPort domain) {
289                if (getRange() != null) {
290                        Object obj = getRange();
291                        if (obj instanceof IOPort)
292                                return ((IOPort) obj).isOutput() == domain.isOutput();
293                        else if (obj instanceof KeplerVirtualIOPort)
294                                return ((KeplerVirtualIOPort) obj).isOutput() == domain
295                                                .isOutput();
296                }
297                return true;
298        }
299
300        /**
301         * @return True if the given range direction matches existing domain
302         *         direction.
303         */
304        private boolean _validateRange(IOPort range) {
305                if (getDomain() != null) {
306                        Object obj = getDomain();
307                        if (obj instanceof IOPort)
308                                return ((IOPort) obj).isOutput() == range.isOutput();
309                        else if (obj instanceof KeplerVirtualIOPort)
310                                return ((KeplerVirtualIOPort) obj).isOutput() == range
311                                                .isOutput();
312                }
313                return true;
314        }
315
316        /**
317         * @return True if the given range direction matches existing domain
318         *         direction.
319         */
320        private boolean _validateRange(KeplerVirtualIOPort range) {
321                if (getDomain() != null) {
322                        Object obj = getDomain();
323                        if (obj instanceof IOPort)
324                                return ((IOPort) obj).isOutput() == range.isOutput();
325                        else if (obj instanceof KeplerVirtualIOPort)
326                                return ((KeplerVirtualIOPort) obj).isOutput() == range
327                                                .isOutput();
328                }
329                return true;
330        }
331
332} // KeplerIOPortSemanticLink