001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.openide.loaders;
043:
044: import junit.textui.TestRunner;
045:
046: import org.openide.filesystems.*;
047: import org.openide.util.Lookup;
048: import java.io.IOException;
049: import java.util.*;
050: import org.netbeans.junit.*;
051: import java.beans.PropertyChangeListener;
052:
053: /** Simulates the deadlock from issue 38554.
054: * @author Jaroslav Tulach
055: */
056: public class Deadlock38554Test extends NbTestCase implements
057: FileChangeListener {
058: private FileSystem lfs;
059: private DataObject src;
060: private DataFolder tgz;
061: private Uni loader;
062:
063: public Deadlock38554Test(String name) {
064: super (name);
065: }
066:
067: protected void setUp() throws Exception {
068: clearWorkDir();
069: lfs = TestUtilHid.createLocalFileSystem(getWorkDir(),
070: new String[] { "folder/", "folder/f.uni", "target/" });
071:
072: loader = (Uni) Uni.getLoader(Uni.class);
073: AddLoaderManuallyHid.addRemoveLoader(loader, true);
074:
075: src = DataObject.find(lfs.findResource("folder/f.uni"));
076: tgz = DataFolder.findFolder(lfs.findResource("target"));
077: lfs.addFileChangeListener(this );
078: }
079:
080: protected void tearDown() throws Exception {
081: lfs.removeFileChangeListener(this );
082: TestUtilHid.destroyLocalFileSystem(getName());
083: AddLoaderManuallyHid.addRemoveLoader(loader, false);
084: }
085:
086: public void testEvilSynchronziedFileChangeListenerWhenCopy()
087: throws Exception {
088: src.copy(tgz);
089: }
090:
091: public void testEvilSynchronziedFileChangeListenerWhenMove()
092: throws Exception {
093: src.move(tgz);
094: }
095:
096: public void testEvilSynchronziedFileChangeListenerWhenCreateFromTemplate()
097: throws Exception {
098: src.createFromTemplate(tgz);
099: }
100:
101: public void testEvilSynchronziedFileChangeListenerWhenCreateFromTemplateWithName()
102: throws Exception {
103: src.createFromTemplate(tgz, "myNewNameOfTheObject");
104: }
105:
106: public void testEvilSynchronziedFileChangeListenerWhenDelete()
107: throws Exception {
108: src.delete();
109: }
110:
111: public void testEvilSynchronziedFileChangeListenerWhenRename()
112: throws Exception {
113: src.rename("myNewName");
114: }
115:
116: //
117: // synchronized listeners
118: //
119:
120: private void block(final FileObject fo) {
121: class OtherThreadAccess implements Runnable {
122: public void run() {
123: try {
124: if (fo.isValid()) {
125: DataObject.find(fo); // should deadlock
126: }
127: } catch (DataObjectNotFoundException ex) {
128: ex.printStackTrace();
129: fail("Error");
130: }
131: }
132: }
133:
134: OtherThreadAccess other = new OtherThreadAccess();
135: org.openide.util.RequestProcessor.getDefault().post(other)
136: .waitFinished(); // should deadlock
137: }
138:
139: public void fileAttributeChanged(FileAttributeEvent fe) {
140: block(fe.getFile());
141: }
142:
143: public void fileChanged(FileEvent fe) {
144: block(fe.getFile());
145: }
146:
147: public void fileDataCreated(FileEvent fe) {
148: block(fe.getFile());
149: }
150:
151: public void fileDeleted(FileEvent fe) {
152: block(fe.getFile());
153: }
154:
155: public void fileFolderCreated(FileEvent fe) {
156: block(fe.getFile());
157: }
158:
159: public void fileRenamed(FileRenameEvent fe) {
160: block(fe.getFile());
161: }
162:
163: public static final class Uni extends UniFileLoader {
164: public Uni() {
165: super (MultiDataObject.class);
166: }
167:
168: protected String displayName() {
169: return "UniLoader";
170: }
171:
172: /** Recognizes just two files - .forget and .keep at once, only in non-forgetable mode
173: */
174: protected synchronized FileObject findPrimaryFile(FileObject fo) {
175: return fo.hasExt("uni") ? fo : null;
176: }
177:
178: protected MultiDataObject createMultiObject(
179: FileObject primaryFile)
180: throws DataObjectExistsException, IOException {
181: return new NotifyObject(primaryFile, this );
182: }
183:
184: protected MultiDataObject.Entry createPrimaryEntry(
185: MultiDataObject obj, FileObject primaryFile) {
186: return new FileEntry(obj, primaryFile);
187: }
188:
189: private class NotifyObject extends MultiDataObject {
190: public NotifyObject(FileObject pf, Uni uni)
191: throws DataObjectExistsException {
192: super (pf, uni);
193: }
194:
195: protected FileObject handleRename(String name)
196: throws IOException {
197: return getPrimaryEntry().rename(name);
198: }
199:
200: protected void handleDelete() throws IOException {
201: getPrimaryEntry().delete();
202: }
203:
204: protected org.openide.loaders.DataObject handleCopy(
205: org.openide.loaders.DataFolder f)
206: throws IOException {
207: FileObject retValue = getPrimaryEntry().copy(
208: f.getPrimaryFile(), "suffix");
209: return new NotifyObject(retValue, (Uni) getLoader());
210: }
211:
212: protected org.openide.loaders.DataShadow handleCreateShadow(
213: org.openide.loaders.DataFolder f)
214: throws IOException {
215: DataShadow retValue;
216: retValue = super .handleCreateShadow(f);
217: return retValue;
218: }
219:
220: protected org.openide.loaders.DataObject handleCreateFromTemplate(
221: org.openide.loaders.DataFolder df, String name)
222: throws IOException {
223: FileObject retValue = getPrimaryEntry()
224: .createFromTemplate(df.getPrimaryFile(), name);
225: return new NotifyObject(retValue, (Uni) getLoader());
226: }
227:
228: protected FileObject handleMove(
229: org.openide.loaders.DataFolder df)
230: throws IOException {
231: FileObject retValue = FileUtil.moveFile(
232: getPrimaryFile(), df.getPrimaryFile(),
233: getPrimaryFile().getNameExt());
234: return retValue;
235: }
236: }
237: }
238:
239: }
|