001/* A BoundaryDetector determines the topological relationship of a Receiver
002 with respect to boundary ports.
003
004 Copyright (c) 1997-2014 The Regents of the University of California.
005 All rights reserved.
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the above
009 copyright notice and the following two paragraphs appear in all copies
010 of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION_2
026 COPYRIGHTENDKEY
027
028
029 */
030package ptolemy.actor.process;
031
032import java.util.Iterator;
033
034import ptolemy.actor.IOPort;
035import ptolemy.actor.Receiver;
036import ptolemy.kernel.ComponentEntity;
037import ptolemy.kernel.util.IllegalActionException;
038import ptolemy.kernel.util.InvalidStateException;
039
040///////////////////////////////////////////////////////////////////
041//// BoundaryDetector
042
043/**
044 A BoundaryDetector determines the topological relationship of a Receiver
045 with respect to boundary ports.
046
047 @author John S. Davis II
048 @version $Id$
049 @since Ptolemy II 1.0
050 @Pt.ProposedRating Red (davisj)
051 @Pt.AcceptedRating Red (davisj)
052
053 */
054public class BoundaryDetector {
055    /** Construct a BoundaryDetector with the specified containing
056     *  receiver.
057     *  @param receiver The receiver containing this BoundaryDetector.
058     */
059    public BoundaryDetector(Receiver receiver) {
060        _receiver = receiver;
061    }
062
063    ///////////////////////////////////////////////////////////////////
064    ////                         public methods                    ////
065
066    /** Return true if the receiver containing this boundary detector
067     *  is connected to a boundary port. A boundary port is an opaque
068     *  port that is contained by a composite actor. If the containing
069     *  receiver is connected to a boundary port, then return true;
070     *  otherwise return false.
071     *  This method is not synchronized so the caller should be.
072     * @return True if the containing receiver is connected to
073     *  boundary port; return false otherwise.
074     * @exception IllegalActionException
075     */
076    public boolean isConnectedToBoundary() throws IllegalActionException {
077        if (_connectedBoundaryCacheIsOn) {
078            return _isConnectedBoundaryValue;
079        } else {
080            IOPort contPort = _receiver.getContainer();
081
082            if (contPort == null) {
083                _connectedBoundaryCacheIsOn = false;
084                _isConnectedBoundaryValue = false;
085                return _isConnectedBoundaryValue;
086            }
087
088            ComponentEntity contEntity = (ComponentEntity) contPort
089                    .getContainer();
090            IOPort connectedPort = null;
091            ComponentEntity connectedEntity = null;
092
093            Iterator ports = contPort.connectedPortList().iterator();
094
095            while (ports.hasNext()) {
096                connectedPort = (IOPort) ports.next();
097                connectedEntity = (ComponentEntity) connectedPort
098                        .getContainer();
099
100                if (connectedEntity == contEntity.getContainer()
101                        && connectedPort.isInput()
102                        && connectedPort.isOpaque()) {
103                    // The port container of this receiver is
104                    // connected to the inside of a boundary port.
105                    // Now determine if this receiver's channel is
106                    // connected to the boundary port.
107                    Receiver[][] receivers = connectedPort.deepGetReceivers();
108
109                    for (Receiver[] receiver : receivers) {
110                        for (int j = 0; j < receiver.length; j++) {
111                            if (_receiver == receiver[j]) {
112                                _connectedBoundaryCacheIsOn = true;
113                                _isConnectedBoundaryValue = true;
114                                return true;
115                            }
116                        }
117                    }
118                } else if (connectedPort.isOpaque()
119                        && !connectedEntity.isAtomic()
120                        && connectedPort.isOutput()) {
121                    // The port container of this receiver is
122                    // connected to the outside of a boundary port.
123                    // Now determine if this receiver's channel is
124                    // connected to the boundary port.
125                    Receiver[][] receivers = connectedPort.getRemoteReceivers();
126
127                    for (Receiver[] receiver : receivers) {
128                        for (int j = 0; j < receiver.length; j++) {
129                            if (_receiver == receiver[j]) {
130                                _connectedBoundaryCacheIsOn = true;
131                                _isConnectedBoundaryValue = true;
132                                return true;
133                            }
134                        }
135                    }
136                }
137            }
138
139            _connectedBoundaryCacheIsOn = true;
140            _isConnectedBoundaryValue = false;
141            return _isConnectedBoundaryValue;
142        }
143    }
144
145    /** Return true if the receiver containing this boundary detector
146     *  is connected to the inside of an input boundary port; return
147     *  false otherwise. A boundary port is an opaque port that is
148     *  contained by a composite actor.
149     *  This method is not synchronized so the caller should be.
150     * @return True if the containing receiver is connected to the
151     *  inside of a boundary port; return false otherwise.
152     * @exception IllegalActionException
153     * @exception InvalidStateException
154     */
155    public boolean isConnectedToBoundaryInside()
156            throws InvalidStateException, IllegalActionException {
157        if (_connectedInsideOfBoundaryCacheIsOn) {
158            return _isConnectedInsideOfBoundaryValue;
159        } else {
160            IOPort contPort = _receiver.getContainer();
161
162            if (contPort == null) {
163                _connectedInsideOfBoundaryCacheIsOn = false;
164                _isConnectedInsideOfBoundaryValue = false;
165                return _isConnectedInsideOfBoundaryValue;
166            }
167
168            ComponentEntity contEntity = (ComponentEntity) contPort
169                    .getContainer();
170            IOPort connectedPort = null;
171            ComponentEntity connectedEntity = null;
172
173            Iterator ports = contPort.connectedPortList().iterator();
174
175            while (ports.hasNext()) {
176                connectedPort = (IOPort) ports.next();
177                connectedEntity = (ComponentEntity) connectedPort
178                        .getContainer();
179
180                if (connectedEntity == contEntity.getContainer()
181                        && connectedPort.isInput()
182                        && connectedPort.isOpaque()) {
183                    // The port container of this receiver is
184                    // connected to the inside of a boundary port.
185                    // Now determine if this receiver's channel is
186                    // connected to the boundary port.
187                    Receiver[][] receivers = connectedPort.deepGetReceivers();
188
189                    for (Receiver[] receiver : receivers) {
190                        for (int j = 0; j < receiver.length; j++) {
191                            if (_receiver == receiver[j]) {
192                                _connectedInsideOfBoundaryCacheIsOn = true;
193                                _isConnectedInsideOfBoundaryValue = true;
194                                return true;
195                            }
196                        }
197                    }
198                }
199            }
200
201            _connectedInsideOfBoundaryCacheIsOn = true;
202            _isConnectedInsideOfBoundaryValue = false;
203            return _isConnectedInsideOfBoundaryValue;
204        }
205    }
206
207    /** Return true if the receiver containing this boundary detector
208     *  is connected to the outside of an output boundary port; return
209     *  false otherwise. A boundary port is an opaque port that is
210     *  contained by a composite actor. If the receiver containing
211     *  this boundary detector is contained on the inside of a boundary
212     *  port, then return false.
213     *  This method is not synchronized so the caller should be.
214     * @return True if the containing receiver is connected to the
215     *  outside of a boundary port; return false otherwise.
216     * @exception IllegalActionException
217     */
218    public boolean isConnectedToBoundaryOutside()
219            throws IllegalActionException {
220        if (_connectedOutsideOfBoundaryCacheIsOn) {
221            return _isConnectedOutsideOfBoundaryValue;
222        } else {
223            IOPort contPort = _receiver.getContainer();
224
225            if (contPort == null) {
226                _connectedOutsideOfBoundaryCacheIsOn = false;
227                _isConnectedOutsideOfBoundaryValue = false;
228                return _isConnectedOutsideOfBoundaryValue;
229            }
230
231            Iterator ports = contPort.connectedPortList().iterator();
232
233            while (ports.hasNext()) {
234                IOPort connectedPort = (IOPort) ports.next();
235                ComponentEntity connectedEntity = (ComponentEntity) connectedPort
236                        .getContainer();
237
238                if (connectedPort.isOpaque() && !connectedEntity.isAtomic()
239                        && connectedPort.isOutput()) {
240                    // The port container of this receiver is
241                    // connected to the outside of a boundary port.
242                    // Now determine if this receiver's channel is
243                    // connected to the boundary port.
244                    Receiver[][] receivers = connectedPort.getRemoteReceivers();
245
246                    for (Receiver[] receiver : receivers) {
247                        for (int j = 0; j < receiver.length; j++) {
248                            if (_receiver == receiver[j]) {
249                                _connectedOutsideOfBoundaryCacheIsOn = true;
250                                _isConnectedOutsideOfBoundaryValue = true;
251                                return true;
252                            }
253                        }
254                    }
255                }
256            }
257
258            _connectedOutsideOfBoundaryCacheIsOn = true;
259            _isConnectedOutsideOfBoundaryValue = false;
260            return _isConnectedOutsideOfBoundaryValue;
261        }
262    }
263
264    /** Return true if the receiver containing this boundary detector
265     *  is contained on the inside of a boundary port. A boundary port
266     *  is an opaque port that is contained by a composite actor. If
267     *  the containing receiver is contained on the inside of a
268     *  boundary port then return true; otherwise return false. This
269     *  method is not synchronized so the caller should be.
270     *  @return True if the containing receiver is contained on the
271     *  inside of a boundary port; return false otherwise.
272     */
273    public boolean isInsideBoundary() {
274        if (_insideBoundaryCacheIsOn) {
275            return _isInsideBoundaryValue;
276        } else {
277            IOPort innerPort = _receiver.getContainer();
278
279            if (innerPort == null) {
280                _insideBoundaryCacheIsOn = false;
281                _isInsideBoundaryValue = false;
282                return _isInsideBoundaryValue;
283            }
284
285            ComponentEntity innerEntity = (ComponentEntity) innerPort
286                    .getContainer();
287
288            if (innerEntity != null && !innerEntity.isAtomic()
289                    && innerPort.isOpaque()) {
290                // The containing receiver is contained by the port
291                // of a composite actor.
292                if (innerPort.isOutput() && !innerPort.isInput()) {
293                    _isInsideBoundaryValue = true;
294                } else if (!innerPort.isOutput() && innerPort.isInput()) {
295                    _isInsideBoundaryValue = false;
296                } else if (!innerPort.isOutput() && !innerPort.isInput()) {
297                    _isInsideBoundaryValue = false;
298                } else {
299                    // CONCERN: The following only works if the port
300                    // is not both an input and output.
301                    throw new IllegalArgumentException("A port that "
302                            + "is both an input and output can not be "
303                            + "properly dealt with by "
304                            + "PNQueueReceiver.isInsideBoundary");
305                }
306
307                _insideBoundaryCacheIsOn = true;
308                return _isInsideBoundaryValue;
309            }
310
311            _insideBoundaryCacheIsOn = true;
312            _isInsideBoundaryValue = false;
313            return _isInsideBoundaryValue;
314        }
315    }
316
317    /** Return true if the receiver containing this boundary detector
318     *  is contained on the outside of a boundary port. A boundary
319     *  port is an opaque port that is contained by a composite actor.
320     *  If the containing receiver is contained on the outside of a
321     *  boundary port then return true; otherwise return false. This
322     *  method is not synchronized so the caller should be.
323     * @return True if the containing receiver is contained on the
324     *  outside of a boundary port; return false otherwise.
325     */
326    public boolean isOutsideBoundary() {
327        if (_outsideBoundaryCacheIsOn) {
328            return _isInsideBoundaryValue;
329        } else {
330            IOPort innerPort = _receiver.getContainer();
331
332            if (innerPort == null) {
333                _outsideBoundaryCacheIsOn = false;
334                _isOutsideBoundaryValue = false;
335                return _isOutsideBoundaryValue;
336            }
337
338            ComponentEntity innerEntity = (ComponentEntity) innerPort
339                    .getContainer();
340
341            if (innerEntity != null && !innerEntity.isAtomic()
342                    && innerPort.isOpaque()) {
343                // The containing receiver is contained by the port
344                // of a composite actor.
345                if (innerPort.isOutput() && !innerPort.isInput()) {
346                    _isOutsideBoundaryValue = false;
347                } else if (!innerPort.isOutput() && innerPort.isInput()) {
348                    _isOutsideBoundaryValue = true;
349                } else if (!innerPort.isOutput() && !innerPort.isInput()) {
350                    _isOutsideBoundaryValue = false;
351                } else {
352                    // CONCERN: The following only works if the port
353                    // is not both an input and output.
354                    throw new IllegalArgumentException("A port that "
355                            + "is both an input and output can not be "
356                            + "properly dealt with by "
357                            + "PNQueueReceiver.isInsideBoundary");
358                }
359
360                _outsideBoundaryCacheIsOn = true;
361                return _isOutsideBoundaryValue;
362            }
363
364            _outsideBoundaryCacheIsOn = true;
365            _isOutsideBoundaryValue = false;
366            return _isOutsideBoundaryValue;
367        }
368    }
369
370    /** Reset the cache variables in boundary detector.
371     */
372    public void reset() {
373        _insideBoundaryCacheIsOn = false;
374        _isInsideBoundaryValue = false;
375        _outsideBoundaryCacheIsOn = false;
376        _isOutsideBoundaryValue = false;
377        _connectedBoundaryCacheIsOn = false;
378        _isConnectedBoundaryValue = false;
379    }
380
381    ///////////////////////////////////////////////////////////////////
382    ////                         private methods                   ////
383    private Receiver _receiver;
384
385    private boolean _insideBoundaryCacheIsOn = false;
386
387    private boolean _isInsideBoundaryValue = false;
388
389    private boolean _outsideBoundaryCacheIsOn = false;
390
391    private boolean _isOutsideBoundaryValue = false;
392
393    private boolean _connectedBoundaryCacheIsOn = false;
394
395    private boolean _isConnectedBoundaryValue = false;
396
397    private boolean _connectedInsideOfBoundaryCacheIsOn = false;
398
399    private boolean _isConnectedInsideOfBoundaryValue = false;
400
401    private boolean _connectedOutsideOfBoundaryCacheIsOn = false;
402
403    private boolean _isConnectedOutsideOfBoundaryValue = false;
404}