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}