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.netbeans.core;
043:
044: import java.beans.PropertyChangeEvent;
045: import java.io.ByteArrayOutputStream;
046: import java.io.IOException;
047: import java.io.InputStream;
048: import java.io.PrintStream;
049: import java.io.StringWriter;
050: import java.net.URL;
051: import java.util.ArrayList;
052: import java.util.Date;
053: import java.util.Enumeration;
054: import java.util.HashMap;
055: import java.util.HashSet;
056: import java.util.Iterator;
057: import java.util.LinkedList;
058: import java.util.regex.Pattern;
059: import javax.swing.event.ChangeEvent;
060: import junit.framework.AssertionFailedError;
061: import junit.framework.TestResult;
062: import org.netbeans.junit.NbTestCase;
063: import org.openide.ErrorManager;
064: import org.openide.util.Enumerations;
065: import org.openide.util.Lookup;
066: import org.openide.util.lookup.AbstractLookup;
067: import org.openide.util.lookup.InstanceContent;
068: import org.openide.util.lookup.Lookups;
069: import org.openide.util.lookup.ProxyLookup;
070:
071: /** Basic skeleton for logging test case in core.
072: *
073: * @author Jaroslav Tulach
074: */
075: public class LoggingTestCaseHid extends NbTestCase {
076: static {
077: org.netbeans.core.startup.MainLookup.register(new ErrManager());
078: }
079:
080: private HashSet unregister = new HashSet();
081:
082: protected LoggingTestCaseHid(String name) {
083: super (name);
084: }
085:
086: public void run(TestResult result) {
087: Lookup l = Lookup.getDefault();
088:
089: assertEquals("We can run only with our Lookup",
090: org.netbeans.core.startup.MainLookup.class, l
091: .getClass());
092:
093: super .run(result);
094:
095: for (Iterator it = unregister.iterator(); it.hasNext();) {
096: Object elem = it.next();
097:
098: org.netbeans.core.startup.MainLookup.unregister(elem);
099: }
100: }
101:
102: /** If execution fails we wrap the exception with
103: * new log message.
104: */
105: protected void runTest() throws Throwable {
106:
107: assertNotNull("ErrManager has to be in lookup", Lookup
108: .getDefault().lookup(ErrManager.class));
109:
110: ErrManager.clear(getName(), getLog());
111:
112: try {
113: super .runTest();
114: } catch (AssertionFailedError ex) {
115: ErrManager.messages.append("\nGot exception: "
116: + ex.getMessage());
117: Thread.sleep(1000);
118: AssertionFailedError ne = new AssertionFailedError(ex
119: .getMessage()
120: + " Log:\n" + ErrManager.messages);
121: ne.setStackTrace(ex.getStackTrace());
122: throw ne;
123: } catch (IOException iex) {//#66208
124: ErrManager.messages.append("\nGot exception: "
125: + iex.getMessage());
126: Thread.sleep(1000);
127: IOException ne = new IOException(iex.getMessage()
128: + " Log:\n" + ErrManager.messages);
129: ne.setStackTrace(iex.getStackTrace());
130: throw ne;
131: }
132: }
133:
134: /** Allows subclasses to register content for the lookup. Can be used in
135: * setUp and test methods, after that the content is cleared.
136: */
137: protected final void registerIntoLookup(Object instance) {
138: unregister.add(instance);
139: org.netbeans.core.startup.MainLookup.register(instance);
140: }
141:
142: //
143: // Logging support
144: //
145: public static final class ErrManager extends ErrorManager {
146: public static final StringBuffer messages = new StringBuffer();
147: static java.io.PrintStream log = System.err;
148:
149: private String prefix;
150:
151: private static LinkedList switches;
152: /** maps names of threads to their instances*/
153: private static java.util.Map threads = new java.util.HashMap();
154:
155: public ErrManager() {
156: this (null);
157: }
158:
159: public ErrManager(String prefix) {
160: this .prefix = prefix;
161: }
162:
163: public Throwable annotate(Throwable t, int severity,
164: String message, String localizedMessage,
165: Throwable stackTrace, Date date) {
166: return t;
167: }
168:
169: public Throwable attachAnnotations(Throwable t,
170: ErrorManager.Annotation[] arr) {
171: return t;
172: }
173:
174: public ErrorManager.Annotation[] findAnnotations(Throwable t) {
175: return null;
176: }
177:
178: public ErrorManager getInstance(String name) {
179: if (true
180: // name.startsWith ("org.openide.loaders.FolderList")
181: // || name.startsWith ("org.openide.loaders.FolderInstance")
182: ) {
183: return new ErrManager('[' + name + "] ");
184: } else {
185: // either new non-logging or myself if I am non-logging
186: return new ErrManager();
187: }
188: }
189:
190: public void log(int severity, String s) {
191: if (prefix != null) {
192: StringBuffer oneMsg = new StringBuffer();
193: oneMsg.append(prefix);
194: oneMsg.append("THREAD:");
195: oneMsg.append(Thread.currentThread().getName());
196: oneMsg.append(" MSG:");
197: oneMsg.append(s);
198:
199: messages.append(oneMsg.toString());
200: messages.append('\n');
201:
202: if (messages.length() > 40000) {
203: messages.delete(0, 20000);
204: }
205:
206: log.println(oneMsg.toString());
207: }
208:
209: if (switches != null) {
210: boolean log = true;
211: boolean expectingMsg = false;
212: for (;;) {
213: synchronized (switches) {
214: if (switches.isEmpty()) {
215: return;
216: }
217:
218: Switch w = (Switch) switches.getFirst();
219: String threadName = Thread.currentThread()
220: .getName();
221: boolean foundMatch = false;
222:
223: if (w.matchesThread()) {
224: if (!w.matchesMessage(s)) {
225: // same thread but wrong message => go on
226: return;
227: }
228: // the correct message from the right thread found
229: switches.removeFirst();
230: if (switches.isEmpty()) {
231: // end of sample
232: return;
233: }
234: w = (Switch) switches.getFirst();
235: if (w.matchesThread()) {
236: // next message is also from this thread, go on
237: return;
238: }
239: expectingMsg = true;
240: foundMatch = true;
241: } else {
242: // compute whether we shall wait or not
243: java.util.Iterator it = switches.iterator();
244: while (it.hasNext()) {
245: Switch check = (Switch) it.next();
246: if (check.matchesMessage(s)) {
247: expectingMsg = true;
248: break;
249: }
250: }
251: }
252:
253: // make it other thread run
254: Thread t = (Thread) threads.get(w.name);
255: if (t != null) {
256: if (log) {
257: messages.append("t: " + threadName
258: + " interrupts: " + t.getName()
259: + "\n");
260: }
261: t.interrupt();
262: }
263: threads.put(threadName, Thread.currentThread());
264:
265: //
266: // if (log) {
267: // messages.append("t: " + Thread.currentThread().getName() + " log: " + s + " result: " + m + " for: " + w + "\n");
268: // }
269: if (!expectingMsg) {
270: return;
271: }
272:
273: // clear any interrupt that happend before
274: Thread.interrupted();
275: try {
276: if (log) {
277: messages.append("t: " + threadName
278: + " log: " + s + " waiting\n");
279: }
280: switches.wait(300);
281: if (log) {
282: messages.append("t: " + threadName
283: + " log: " + s + " timeout\n");
284: }
285: return;
286: } catch (InterruptedException ex) {
287: // ok, we love to be interrupted => go on
288: if (log) {
289: messages.append("t: " + threadName
290: + " log: " + s
291: + " interrupted\n");
292: }
293: if (foundMatch) {
294: return;
295: }
296: }
297: }
298: }
299: }
300: }
301:
302: public void notify(int severity, Throwable t) {
303: log(severity, t.getMessage());
304: }
305:
306: public boolean isNotifiable(int severity) {
307: return prefix != null;
308: }
309:
310: public boolean isLoggable(int severity) {
311: return prefix != null;
312: }
313:
314: private static void clear(String n, PrintStream printStream) {
315: ErrManager.log = printStream;
316: ErrManager.messages.setLength(0);
317: ErrManager.messages.append("Starting test ");
318: ErrManager.messages.append(n);
319: ErrManager.messages.append('\n');
320: }
321:
322: } // end of ErrManager
323:
324: private static final class Switch {
325: private Pattern msg;
326: private String name;
327:
328: public Switch(String n, Pattern m) {
329: this .name = n;
330: this .msg = m;
331: }
332:
333: /** @return true if the thread name of the caller matches this switch
334: */
335: public boolean matchesThread() {
336: String thr = Thread.currentThread().getName();
337: return name.equals(thr);
338: }
339:
340: /** @return true if the message matches the one provided by this switch
341: */
342: public boolean matchesMessage(String logMsg) {
343: return msg.matcher(logMsg).matches();
344: }
345:
346: public String toString() {
347: return "Switch[" + name + "]: " + msg;
348: }
349: }
350: }
|