001/* Test for ChangeRequest.
002
003 Copyright (c) 1998-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
027 */
028package ptolemy.kernel.util.test.system;
029
030import java.util.Collections;
031import java.util.Enumeration;
032
033import ptolemy.actor.IORelation;
034import ptolemy.actor.Manager;
035import ptolemy.actor.TypedCompositeActor;
036import ptolemy.actor.lib.AddSubtract;
037import ptolemy.actor.lib.Const;
038import ptolemy.actor.lib.Recorder;
039import ptolemy.data.DoubleToken;
040import ptolemy.domains.sdf.kernel.SDFDirector;
041import ptolemy.domains.sdf.lib.SampleDelay;
042import ptolemy.kernel.ComponentRelation;
043import ptolemy.kernel.util.ChangeListener;
044import ptolemy.kernel.util.ChangeRequest;
045import ptolemy.kernel.util.IllegalActionException;
046import ptolemy.kernel.util.KernelException;
047import ptolemy.kernel.util.NameDuplicationException;
048
049///////////////////////////////////////////////////////////////////
050//// ChangeRequestTest
051
052/**
053 Test for ChangeRequest.
054
055 This test is in the system directory because it uses packages outside
056 of kernel.util.
057
058 @author  Edward A. Lee, Contributor: Christopher Hylands
059 @version $Id$
060 @since Ptolemy II 10.0
061 @Pt.ProposedRating Red (eal)
062 @Pt.AcceptedRating Red (reviewmoderator)
063 @see ptolemy.kernel.util.ChangeRequest
064
065 */
066public class ChangeRequestTest implements ChangeListener {
067    /** Constructor.
068     */
069    public ChangeRequestTest()
070            throws IllegalActionException, NameDuplicationException {
071        _top = new TypedCompositeActor();
072        _top.setName("top");
073        _manager = new Manager();
074
075        SDFDirector director = new SDFDirector();
076        _top.setDirector(director);
077        _top.setManager(_manager);
078
079        _top.addChangeListener(this);
080        _const = new Const(_top, "const");
081        _rec = new Recorder(_top, "rec");
082        IORelation relation = (IORelation) _top.connect(_const.output,
083                _rec.input);
084        relation.setWidth(1);
085    }
086
087    ///////////////////////////////////////////////////////////////////
088    ////                         public methods                    ////
089
090    /** React to a change request has been successfully executed by
091     *  doing nothing. This method is called after a change request
092     *  has been executed successfully.  In this class, we
093     *  do nothing.
094     *  @param change The change that has been executed, or null if
095     *   the change was not done via a ChangeRequest.
096     */
097    @Override
098    public void changeExecuted(ChangeRequest change) {
099    }
100
101    /** React to a change request that has resulted in an exception.
102     *  This method is called after a change request was executed,
103     *  but during the execution in an exception was thrown.
104     *  This method throws a runtime exception with a description
105     *  of the original exception.
106     *  @param change The change that was attempted or null if
107     *   the change was not done via a ChangeRequest.
108     *  @param exception The exception that resulted.
109     */
110    @Override
111    public void changeFailed(ChangeRequest change, Exception exception) {
112        // If we do not implement ChangeListener, then ChangeRequest
113        // will print any errors to stdout and continue.
114        // This causes no end of trouble with the test suite
115        // We can't throw and Exception here because this method in
116        // the base class does not throw Exception.
117        // In JDK1.4, we can construct exceptions from exceptions, but
118        // not in JDK1.3.1
119        //throw new RuntimeException(exception);
120        throw new RuntimeException(exception.toString());
121    }
122
123    /** Finish a run.  Return the results.
124     */
125    public Enumeration finish() throws KernelException {
126        for (int i = 0; i < 4; i++) {
127            _manager.iterate();
128        }
129
130        _manager.wrapup();
131        return Collections.enumeration(_rec.getHistory(0));
132    }
133
134    /** Insert a feedback loop.
135     */
136    public void insertFeedback() {
137        // Create an anonymous inner class
138        ChangeRequest change = new ChangeRequest(this, "test2") {
139            @Override
140            protected void _execute() throws Exception {
141                _const.output.unlinkAll();
142                _rec.input.unlinkAll();
143
144                AddSubtract add = new AddSubtract(_top, "add");
145                SampleDelay sampleDelay = new SampleDelay(_top, "sampleDelay");
146                sampleDelay.initialOutputs.setExpression("{4, 5}");
147                _top.connect(_const.output, add.plus);
148
149                ComponentRelation relation = _top.connect(add.output,
150                        sampleDelay.input);
151                _rec.input.link(relation);
152
153                // Any pre-existing input port whose connections
154                // are modified needs to have this method called.
155                _rec.input.createReceivers();
156                _top.connect(sampleDelay.output, add.plus);
157            }
158        };
159
160        _top.requestChange(change);
161    }
162
163    /** Mutate.
164     */
165    public void mutate() {
166        if (changeRequest == null) {
167            changeRequest = mutateConst2ChangeRequest();
168        }
169
170        _top.requestChange(changeRequest);
171    }
172
173    public void waitForCompletionTask() {
174        Thread waitForCompletionThread = new Thread(new Runnable() {
175            @Override
176            public void run() {
177                System.out.println(Thread.currentThread().getName()
178                        + " About to wait for completion");
179
180                try {
181                    changeRequest.waitForCompletion();
182                } catch (Exception ex) {
183                    System.out.println(ex);
184                }
185
186                System.out.println(Thread.currentThread().getName()
187                        + " Done waiting for completion");
188            }
189        });
190
191        waitForCompletionThread.setName("waitForCompletionThread");
192        waitForCompletionThread.start();
193    }
194
195    /** Create a change request that always throws an exception. */
196    public ChangeRequest mutateBadChangeRequest() {
197        // Create an anonymous inner class
198        changeRequest = new ChangeRequest(this,
199                "Change request that always throws an Exception") {
200            @Override
201            protected void _execute() throws Exception {
202                // Compare against true so that the code compiles.
203                if (true) {
204                    throw new Exception("Always Thrown Exception");
205                }
206            }
207        };
208        return changeRequest;
209    }
210
211    /** Create a change request that sets const to 2.0. */
212    public ChangeRequest mutateConst2ChangeRequest() {
213        // Create an anonymous inner class
214        changeRequest = new ChangeRequest(this, "Changing Const to 2.0") {
215            @Override
216            protected void _execute() throws Exception {
217                _const.value.setToken(new DoubleToken(2.0));
218            }
219        };
220        return changeRequest;
221    }
222
223    /** Start a run.
224     */
225    public void start() throws KernelException {
226        _manager.initialize();
227        _manager.iterate();
228    }
229
230    ///////////////////////////////////////////////////////////////////
231    ////                         public variables                  ////
232
233    /** ChangeRequest that modifies the system. */
234    public ChangeRequest changeRequest;
235
236    ///////////////////////////////////////////////////////////////////
237    ////                         private variables                 ////
238    private Manager _manager;
239
240    private Recorder _rec;
241
242    private Const _const;
243
244    private TypedCompositeActor _top;
245}