001/* For testing the workspace synchronization features.
002
003 Copyright (c) 1997-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
028 */
029package ptolemy.kernel.util.test;
030
031import ptolemy.kernel.util.Workspace;
032
033///////////////////////////////////////////////////////////////////
034//// TestWorkspace2
035
036/**
037 This object implements a thread that obtains read permission to
038 a workspace three times sequentially, then calls workspace.wait(obj) on an
039 object and exits. The object "obj" on which the wait method is called is an
040 inner class of TestWorkspace2 and has a thread of its own. This thread gets a
041 write access on the workspace, after the TestWorkspace2 object calls wait(obj)
042 on it. Then it gives up the write access and returns.
043 To use it, create an instance and then call its start() method.
044 To obtain a profile of what it did, call its profile() method.
045 That will return only after the thread completes.
046 NOTE: This is a very primitive test.  It does not check very much.
047
048 @author Mudit Goel, Edward A. Lee
049 @version $Id$
050 @since Ptolemy II 0.3
051 @Pt.ProposedRating Green (eal)
052 @Pt.AcceptedRating Red (cxh)
053
054 */
055public class TestWorkspace2 extends Thread {
056    public static void main(String[] args) {
057        Workspace w = new Workspace("test");
058        TestWorkspace2 tw = new TestWorkspace2("test", w);
059        tw.start();
060        System.out.println(tw.profile);
061    }
062
063    public TestWorkspace2(String name, Workspace workspace) {
064        _name = name;
065        _workspace = workspace;
066        _notif = new Notification(_name + ".notif");
067    }
068
069    /** Start a thread for an instance of the inner class "Notification",
070     *  obtain read access on the workspace 3 times, call wait(obj) on the
071     *  workspace, ask the inner class to get a write access on the workspace
072     *  and return after relinquishing the read accesses on the workspace.
073     *  This method is synchronized both on this class and the inner class
074     */
075    @Override
076    public synchronized void run() {
077        _notif.start();
078
079        int i = 0;
080
081        try {
082            for (i = 0; i < 3; i++) {
083                _workspace.getReadAccess();
084                profile += _name + ".getReadAccess()\n";
085
086                try {
087                    // FindBugs:
088                    // [M M SWL] Method calls Thread.sleep() with a lock held [SWL_SLEEP_WITH_LOCK_HELD]
089                    // In this test program however this is not a problem.
090                    Thread.sleep(100);
091                } catch (InterruptedException ex) {
092                }
093            }
094
095            // NOTE: we must synchronize with _notif to not miss notifications
096            // (we make sure that the other thread only starts once we have
097            // called wait.
098            synchronized (_notif) {
099                _notif.getWriteAccess = true;
100
101                // Remark:
102                //      The while (_notif.getWriteAccess) is not
103                //      necessary in the current implementation (with
104                //      only two threads using _notif), but makes it
105                //      more robust when changes are made.
106                //      This problem was detected by Findbugs:
107                //        UW: Unconditional wait (UW_UNCOND_WAIT)
108                while (_notif.getWriteAccess) {
109                    try {
110                        _workspace.wait(_notif);
111                    } catch (InterruptedException e) {
112                        e.printStackTrace();
113                    }
114                }
115
116                _notif.done = true;
117            }
118        } finally {
119            for (int j = i; j > 0; j--) {
120                _workspace.doneReading();
121                profile += _name + ".doneReading()\n";
122            }
123        }
124    }
125
126    /** Return a profile which contains the various actions performed by this
127     *  object.
128     */
129    public synchronized String profile() {
130        return profile;
131    }
132
133    public Workspace _workspace;
134
135    public String profile = "";
136
137    private Notification _notif;
138
139    private String _name;
140
141    ///////////////////////////////////////////////////////////////////
142    ////                         inner class                       ////
143
144    /** Repeatedly calls notifyAll on itself to wake up any threads waiting
145     *  on it.
146     */
147    public class Notification extends Thread {
148        public Notification(String name) {
149            _name = name;
150        }
151
152        @Override
153        public void run() {
154            while (!done) {
155                try {
156                    Thread.sleep(100);
157                } catch (InterruptedException ex) {
158                }
159
160                synchronized (this) {
161                    if (getWriteAccess) {
162                        try {
163                            TestWorkspace2.this._workspace.getWriteAccess();
164                            TestWorkspace2.this.profile += _name
165                                    + ".getWriteAccess()\n";
166                        } finally {
167                            _workspace.doneWriting();
168                            TestWorkspace2.this.profile += _name
169                                    + ".doneWriting()\n";
170                        }
171
172                        getWriteAccess = false;
173                        notifyAll();
174                    }
175                }
176            }
177        }
178
179        public boolean done = false;
180
181        public boolean getWriteAccess = false;
182
183        public String _name;
184    }
185}