Return-Path: Delivered-To: apmail-geronimo-scm-archive@www.apache.org Received: (qmail 27412 invoked from network); 27 Mar 2008 07:17:49 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 27 Mar 2008 07:17:49 -0000 Received: (qmail 94490 invoked by uid 500); 27 Mar 2008 07:17:48 -0000 Delivered-To: apmail-geronimo-scm-archive@geronimo.apache.org Received: (qmail 94482 invoked by uid 500); 27 Mar 2008 07:17:48 -0000 Mailing-List: contact scm-help@geronimo.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: dev@geronimo.apache.org List-Id: Delivered-To: mailing list scm@geronimo.apache.org Received: (qmail 94473 invoked by uid 99); 27 Mar 2008 07:17:48 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 27 Mar 2008 00:17:48 -0700 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 27 Mar 2008 07:17:16 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 96F6D1A9832; Thu, 27 Mar 2008 00:17:18 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r641723 - in /geronimo/gshell/trunk/gshell-support/gshell-common/src: main/java/org/apache/geronimo/gshell/common/ test/java/org/apache/geronimo/gshell/common/ Date: Thu, 27 Mar 2008 07:17:17 -0000 To: scm@geronimo.apache.org From: jdillon@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080327071726.96F6D1A9832@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: jdillon Date: Thu Mar 27 00:17:16 2008 New Revision: 641723 URL: http://svn.apache.org/viewvc?rev=641723&view=rev Log: (GSHELL-89) Bring over the system hijacking code from the groovy-maven-plugin stuff, tidy up for Java 5 Added: geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/StreamPair.java (with props) geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/SystemOutputHijacker.java (with props) geronimo/gshell/trunk/gshell-support/gshell-common/src/test/java/org/apache/geronimo/gshell/common/SystemOutputHijackerTest.java (with props) Added: geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/StreamPair.java URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/StreamPair.java?rev=641723&view=auto ============================================================================== --- geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/StreamPair.java (added) +++ geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/StreamPair.java Thu Mar 27 00:17:16 2008 @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.geronimo.gshell.common; + +import org.apache.geronimo.gshell.common.tostring.ReflectionToStringBuilder; +import org.apache.geronimo.gshell.common.tostring.ToStringStyle; + +import java.io.PrintStream; + +/** + * Contains a pair of {@link PrintStream} objects. + * + * @version $Rev$ $Date$ + */ +public class StreamPair +{ + public final PrintStream out; + + public final PrintStream err; + + public final boolean combined; + + public StreamPair(final PrintStream out, final PrintStream err) { + assert out != null; + assert err != null; + + this.out = out; + this.err = err; + this.combined = (out == err); + } + + public StreamPair(final PrintStream out) { + assert out != null; + + this.out = out; + this.err = out; + this.combined = true; + } + + public PrintStream get(final Type type) { + assert type != null; + + return type.get(this); + } + + public String toString() { + return ReflectionToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); + } + + public void flush() { + out.flush(); + + if (!combined) { + err.flush(); + } + } + + public void close() { + out.close(); + + if (!combined) { + err.close(); + } + } + + /** + * Create a new pair as System is currently configured. + */ + public static StreamPair system() { + return new StreamPair(System.out, System.err); + } + + /** + * Install the given stream pair as the System streams. + */ + public static void system(final StreamPair streams) { + assert streams != null; + + System.setOut(streams.out); + System.setErr(streams.err); + } + + /** + * The original System streams (as they were when this class loads). + */ + public static final StreamPair SYSTEM = system(); + + /** + * Stream type. + */ + public static enum Type + { + OUT, ERR; + + private PrintStream get(final StreamPair pair) { + assert pair != null; + + switch (this) { + case OUT: + return pair.out; + + case ERR: + return pair.err; + } + + // Should never happen + throw new InternalError(); + } + } +} Propchange: geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/StreamPair.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/StreamPair.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/StreamPair.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/SystemOutputHijacker.java URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/SystemOutputHijacker.java?rev=641723&view=auto ============================================================================== --- geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/SystemOutputHijacker.java (added) +++ geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/SystemOutputHijacker.java Thu Mar 27 00:17:16 2008 @@ -0,0 +1,268 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.geronimo.gshell.common; + +import java.io.PrintStream; +import java.io.IOException; +import java.io.ByteArrayOutputStream; + +/** + * Hijacks the systems standard output and error streams on a per-thread basis + * and redirects to given streams. + * + * @version $Rev$ $Date$ + */ +public class SystemOutputHijacker +{ + /** + * Contains a {@link StreamRegistration} for the current thread if its registered, else null. + */ + private static final InheritableThreadLocal registrations = new InheritableThreadLocal(); + + /** + * The previously installed System streams, initialized when installing. + */ + private static StreamPair previous; + + /** + * Flag to indicate if the hijacker is installed or not. + */ + private static boolean installed; + + /** + * Check if the hijacker has been installed. + */ + public static synchronized boolean isInstalled() { + return installed; + } + + private static synchronized void ensureInstalled() { + if (!isInstalled()) { + throw new IllegalStateException("Not installed"); + } + } + + /** + * Install the hijacker. + */ + public static synchronized void install() { + if (installed) { + throw new IllegalStateException("Already installed"); + } + + // Capture the current set of streams + previous = new StreamPair(System.out, System.err); + + // Install our streams + System.setOut(new DelegateStream(StreamPair.Type.OUT)); + System.setErr(new DelegateStream(StreamPair.Type.ERR)); + + installed = true; + } + + /** + * Install the hijacker and register streams for the current thread. + */ + public static synchronized void install(final PrintStream out, final PrintStream err) { + install(); + register(out, err); + } + + /** + * Install the hijacker and register combinded streams for the current thread. + */ + public static synchronized void install(final PrintStream out) { + install(); + register(out); + } + + /** + * Uninstall the hijacker. + */ + public static synchronized void uninstall() { + ensureInstalled(); + + System.setOut(previous.out); + System.setErr(previous.err); + + previous = null; + installed = false; + } + + /** + * Get the current stream registration. + */ + private static synchronized StreamRegistration registration(final boolean required) { + if (required) { + ensureRegistered(); + } + + return registrations.get(); + } + + /** + * Check if there are streams registered for the current thread. + */ + public static synchronized boolean isRegistered() { + return registration(false) != null; + } + + private static synchronized void ensureRegistered() { + ensureInstalled(); + + if (!isRegistered()) { + throw new IllegalStateException("Streams not registered for thread: " + Thread.currentThread()); + } + } + + /** + * Register streams for the current thread. + */ + public static synchronized void register(final PrintStream out, final PrintStream err) { + ensureInstalled(); + + StreamRegistration prev = registration(false); + + StreamPair pair = new StreamPair(out, err); + + StreamRegistration next = new StreamRegistration(pair, prev); + + registrations.set(next); + } + + /** + * Register combinded streams for the current thread. + */ + public static synchronized void register(final PrintStream out) { + register(out, out); + } + + /** + * Register streams for the current thread. + */ + public static synchronized void register(final StreamPair pair) { + assert pair != null; + + register(pair.out, pair.err); + } + + /** + * Reregister streams for the current thread, and restore the previous if any. + */ + public static synchronized void deregister() { + StreamRegistration cur = registration(true); + + registrations.set(cur.previous); + } + + /** + * Stream registration information. + */ + private static class StreamRegistration + { + public final StreamPair streams; + + public final StreamRegistration previous; + + public StreamRegistration(final StreamPair streams, final StreamRegistration previous) { + assert streams != null; + + this.streams = streams; + this.previous = previous; + } + } + + /** + * Returns the currently registered streams. + */ + private static synchronized StreamPair current() { + StreamRegistration reg = registration(true); + + return reg.streams; + } + + /** + * Delegates write calls to the currently registered stream. + */ + private static class DelegateStream + extends PrintStream + { + private static final ByteArrayOutputStream NULL_OUTPUT = new ByteArrayOutputStream(); + + private final StreamPair.Type type; + + public DelegateStream(final StreamPair.Type type) { + super(NULL_OUTPUT); + + assert type != null; + + this.type = type; + } + + private PrintStream get() { + return current().get(type); + } + + public void write(final int b) { + get().write(b); + } + + public void write(final byte b[]) throws IOException { + get().write(b, 0, b.length); + } + + public void write(final byte[] b, final int off, final int len) { + get().write(b, off, len); + } + + public void flush() { + get().flush(); + } + + public void close() { + get().close(); + } + } + + // + // System Stream Restoration. This stuff needs more testing, not sure its working as I'd like... :-( + // + + /** + * Restores the System streams to the given pair and resets the hijacker state to uninstalled. + */ + public static synchronized void restore(final StreamPair streams) { + assert streams != null; + + StreamPair.system(streams); + + previous = null; + installed = false; + } + + /** + * Restores the original System streams from {@link StreamPair#SYSTEM} and resets + * the hijacker state to uninstalled. + */ + public static synchronized void restore() { + restore(StreamPair.SYSTEM); + } + +} Propchange: geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/SystemOutputHijacker.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/SystemOutputHijacker.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: geronimo/gshell/trunk/gshell-support/gshell-common/src/main/java/org/apache/geronimo/gshell/common/SystemOutputHijacker.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/gshell/trunk/gshell-support/gshell-common/src/test/java/org/apache/geronimo/gshell/common/SystemOutputHijackerTest.java URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-support/gshell-common/src/test/java/org/apache/geronimo/gshell/common/SystemOutputHijackerTest.java?rev=641723&view=auto ============================================================================== --- geronimo/gshell/trunk/gshell-support/gshell-common/src/test/java/org/apache/geronimo/gshell/common/SystemOutputHijackerTest.java (added) +++ geronimo/gshell/trunk/gshell-support/gshell-common/src/test/java/org/apache/geronimo/gshell/common/SystemOutputHijackerTest.java Thu Mar 27 00:17:16 2008 @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.geronimo.gshell.common; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import junit.framework.TestCase; + +/** + * Tests for the {@link SystemOutputHijacker} class. + * + * @version $Rev$ $Date$ + */ +public class SystemOutputHijackerTest + extends TestCase +{ + private ByteArrayOutputStream buff; + + private PrintStream out; + + protected void setUp() throws Exception { + buff = new ByteArrayOutputStream(); + out = new PrintStream(buff); + + assertFalse(SystemOutputHijacker.isInstalled()); + } + + protected void tearDown() throws Exception { + buff = null; + out = null; + + assertFalse(SystemOutputHijacker.isInstalled()); + } + + private void installOut() throws Exception { + assertFalse(SystemOutputHijacker.isRegistered()); + + SystemOutputHijacker.install(out); + + assertTrue(SystemOutputHijacker.isInstalled()); + assertTrue(SystemOutputHijacker.isRegistered()); + } + + private void deregisterAndUninstall() throws Exception { + SystemOutputHijacker.deregister(); + + assertFalse(SystemOutputHijacker.isRegistered()); + + SystemOutputHijacker.uninstall(); + + assertFalse(SystemOutputHijacker.isInstalled()); + } + + public void testInstallWithStream() throws Exception { + System.out.println("before"); + + installOut(); + + try { + System.out.print("hijacked"); + } + finally { + deregisterAndUninstall(); + } + + System.out.println("after"); + + String msg = new String(buff.toByteArray()); + + assertEquals("hijacked", msg); + } + + public void testInstallRegisterWithStream() throws Exception { + System.out.println("before"); + + SystemOutputHijacker.install(); + assertTrue(SystemOutputHijacker.isInstalled()); + + assertFalse(SystemOutputHijacker.isRegistered()); + SystemOutputHijacker.register(out); + assertTrue(SystemOutputHijacker.isRegistered()); + + try { + System.out.print("hijacked"); + } + finally { + deregisterAndUninstall(); + } + + System.out.println("after"); + + String msg = new String(buff.toByteArray()); + + assertEquals("hijacked", msg); + } + + public void testDualStreams() throws Exception { + ByteArrayOutputStream errBuff = new ByteArrayOutputStream(); + PrintStream err = new PrintStream(errBuff); + + System.out.println("before"); + System.err.println("BEFORE"); + + SystemOutputHijacker.install(out, err); + + assertTrue(SystemOutputHijacker.isInstalled()); + assertTrue(SystemOutputHijacker.isRegistered()); + + try { + System.out.print("hijacked"); + System.err.print("HIJACKED"); + } + finally { + deregisterAndUninstall(); + } + + System.out.println("after"); + System.err.println("AFTER"); + + assertEquals("hijacked", new String(buff.toByteArray())); + assertEquals("HIJACKED", new String(errBuff.toByteArray())); + } + + public void testChildThreads() throws Exception { + System.out.println("before"); + + installOut(); + + Runnable task = new Runnable() { + public void run() { + System.out.print("hijacked"); + } + }; + + try { + System.out.print("<"); + + Thread t = new Thread(task); + t.start(); + t.join(); + + System.out.print(">"); + } + finally { + deregisterAndUninstall(); + } + + System.out.println("after"); + + String msg = new String(buff.toByteArray()); + + assertEquals("", msg); + } + + public void testNestedRegistration() throws Exception { + System.out.println("before"); + + installOut(); + + try { + System.out.print("hijacked"); + + ByteArrayOutputStream childBuff = new ByteArrayOutputStream(); + PrintStream childOut = new PrintStream(childBuff); + + System.out.print("!"); + + SystemOutputHijacker.register(childOut); + + try { + System.out.print("child"); + } + finally { + SystemOutputHijacker.deregister(); + } + + System.out.print("!"); + + assertEquals("child", new String(childBuff.toByteArray())); + } + finally { + deregisterAndUninstall(); + } + + System.out.println("after"); + + String msg = new String(buff.toByteArray()); + + assertEquals("hijacked!!", msg); + } +} Propchange: geronimo/gshell/trunk/gshell-support/gshell-common/src/test/java/org/apache/geronimo/gshell/common/SystemOutputHijackerTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/gshell/trunk/gshell-support/gshell-common/src/test/java/org/apache/geronimo/gshell/common/SystemOutputHijackerTest.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: geronimo/gshell/trunk/gshell-support/gshell-common/src/test/java/org/apache/geronimo/gshell/common/SystemOutputHijackerTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain