├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── checkstyle.xml ├── findbugsfilter.xml ├── functional-tests ├── no-system-jar-on-classpath │ ├── pom.xml │ └── src │ │ └── test │ │ └── java │ │ └── uk │ │ └── org │ │ └── lidalia │ │ └── sysoutslf4j │ │ └── SysoutOverSlf4jWithNoSystemJarOnClasspathTests.java ├── pom.xml ├── sysout-over-slf4j-webapps │ ├── pom.xml │ └── webapp-with-jdk14 │ │ ├── pom.xml │ │ └── src │ │ └── main │ │ ├── java │ │ └── uk │ │ │ └── org │ │ │ └── lidalia │ │ │ └── sysoutslf4j │ │ │ └── webapps │ │ │ ├── LoggerServlet.java │ │ │ ├── LoggingFilter.java │ │ │ └── PrinterServlet.java │ │ └── webapp │ │ ├── META-INF │ │ └── MANIFEST.MF │ │ └── WEB-INF │ │ └── web.xml └── tests │ └── pom.xml ├── pmd-rules.xml ├── pom.xml ├── src └── site │ ├── apt │ ├── index.apt.vm │ └── quickstart.apt.vm │ ├── fml │ └── faq.fml.vm │ └── site.xml ├── sysout-over-slf4j-context ├── pom.xml └── src │ ├── main │ ├── .gitignore │ └── java │ │ └── uk │ │ └── org │ │ └── lidalia │ │ └── sysoutslf4j │ │ └── context │ │ ├── CallOrigin.java │ │ ├── LoggingMessages.java │ │ ├── LoggingOutputStream.java │ │ ├── LoggingSystemRegister.java │ │ ├── ReferenceHolder.java │ │ ├── ServletContextListener.java │ │ ├── StringUtils.java │ │ ├── SysOutOverSLF4J.java │ │ ├── SysOutOverSLF4JSystemJarNotPresentException.java │ │ ├── exceptionhandlers │ │ ├── ExceptionHandlingStrategy.java │ │ ├── ExceptionHandlingStrategyFactory.java │ │ └── LogPerLineExceptionHandlingStrategyFactory.java │ │ ├── jul │ │ └── ConsoleHandler.java │ │ ├── log4j │ │ └── ConsoleAppender.java │ │ └── logback │ │ └── ConsoleAppender.java │ └── test │ ├── .gitignore │ └── java │ └── uk │ └── org │ └── lidalia │ ├── sysoutslf4j │ ├── SysOutOverSLF4JTestCase.java │ ├── context │ │ ├── CallOriginTests.java │ │ ├── LoggingOutputStreamTests.java │ │ ├── LoggingSystemRegisterTests.java │ │ ├── ReferenceHolderTests.java │ │ ├── ServletContextListenerTests.java │ │ ├── StringUtilsTests.java │ │ ├── SysOutOverSLF4JNotInstantiableTest.java │ │ ├── SysOutOverSLF4JTests.java │ │ ├── exceptionhandlers │ │ │ └── TestLogPerLineExceptionHandlingStrategyFactory.java │ │ ├── jul │ │ │ └── ConsoleHandlerTests.java │ │ ├── log4j │ │ │ └── ConsoleAppenderTests.java │ │ └── logback │ │ │ └── ConsoleAppenderTests.java │ └── integration │ │ ├── CrossClassLoaderTestUtils.java │ │ ├── ISysOutUser.java │ │ ├── SysOutUser.java │ │ ├── TestForClassloaderLeaks.java │ │ ├── TestSysOutOverSLF4JInClassLoader.java │ │ ├── TestSysOutOverSLF4JThreadSafety.java │ │ └── TestSysOutOverSlf4J.java │ └── testutils │ ├── ClassCreationUtils.java │ └── SimpleClassloader.java └── sysout-over-slf4j-system ├── pom.xml └── src ├── main └── java │ └── uk │ └── org │ └── lidalia │ └── sysoutslf4j │ └── system │ ├── PerContextPrintStream.java │ ├── PerContextStore.java │ ├── PerContextSystemOutput.java │ └── SystemOutput.java └── test └── java └── uk └── org └── lidalia └── sysoutslf4j └── system ├── PerContextPrintStreamTests.java ├── PerContextStoreMemoryManagementTests.java ├── PerContextStoreTests.java ├── PerContextSystemOutputTests.java ├── SysOutOverSLF4JTestCase.java └── SystemOutputTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | .settings 2 | target 3 | .classpath 4 | .project 5 | *.iml 6 | *.ipr 7 | *.iws 8 | *~ 9 | integration/bundle/ 10 | integration/felix-cache 11 | integration/felix-cache//.settings 12 | .pmd 13 | bin 14 | .DS_Store 15 | /reports 16 | release.properties 17 | .idea 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - openjdk7 4 | - oraclejdk7 5 | - oraclejdk8 6 | install: true 7 | script: mvn verify 8 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | -------------------------------------------------------------------------------- /checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /findbugsfilter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /functional-tests/no-system-jar-on-classpath/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | uk.org.lidalia.sysout-over-slf4j 5 | functional-tests 6 | 2.0.0-SNAPSHOT 7 | 8 | no-system-jar-on-classpath 9 | No System Jar on Classpath Tests 10 | Tests demonstrating behaviour when sysout-over-slf4j-context is on the classpath 11 | but sysout-over-slf4j-system is not. 12 | 13 | 14 | uk.org.lidalia 15 | lidalia-test-dependencies 16 | pom 17 | 18 | 19 | ${project.groupId} 20 | sysout-over-slf4j-context 21 | ${project.version} 22 | test 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /functional-tests/no-system-jar-on-classpath/src/test/java/uk/org/lidalia/sysoutslf4j/SysoutOverSlf4jWithNoSystemJarOnClasspathTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j; 26 | 27 | import org.junit.Test; 28 | 29 | import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J; 30 | import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4JSystemJarNotPresentException; 31 | 32 | import static org.junit.Assert.assertEquals; 33 | import static uk.org.lidalia.test.ShouldThrow.shouldThrow; 34 | 35 | public class SysoutOverSlf4jWithNoSystemJarOnClasspathTests { 36 | 37 | @Test 38 | public void sendSystemOutAndErrToSLF4JWithoutSystemJarOnClasspath() { 39 | SysOutOverSLF4JSystemJarNotPresentException exception = shouldThrow(SysOutOverSLF4JSystemJarNotPresentException.class, new Runnable() { 40 | @Override 41 | public void run() { 42 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); 43 | } 44 | }); 45 | 46 | assertEquals(SysOutOverSLF4JSystemJarNotPresentException.MESSAGE, exception.getMessage()); 47 | } 48 | 49 | @Test 50 | public void stopSendingSystemOutAndErrToSLF4JWithoutSystemJarOnClasspath() { 51 | SysOutOverSLF4JSystemJarNotPresentException exception = shouldThrow(SysOutOverSLF4JSystemJarNotPresentException.class, new Runnable() { 52 | @Override 53 | public void run() { 54 | SysOutOverSLF4J.stopSendingSystemOutAndErrToSLF4J(); 55 | } 56 | }); 57 | 58 | assertEquals(SysOutOverSLF4JSystemJarNotPresentException.MESSAGE, exception.getMessage()); 59 | } 60 | 61 | @Test 62 | public void restoreOriginalSystemOutputsWithoutSystemJarOnClasspath() { 63 | SysOutOverSLF4JSystemJarNotPresentException exception = shouldThrow(SysOutOverSLF4JSystemJarNotPresentException.class, new Runnable() { 64 | @Override 65 | public void run() { 66 | SysOutOverSLF4J.restoreOriginalSystemOutputs(); 67 | } 68 | }); 69 | 70 | assertEquals(SysOutOverSLF4JSystemJarNotPresentException.MESSAGE, exception.getMessage()); 71 | } 72 | 73 | @Test 74 | public void systemOutputsAreSLF4JPrintStreamsWithoutSystemJarOnClasspath() { 75 | SysOutOverSLF4JSystemJarNotPresentException exception = shouldThrow(SysOutOverSLF4JSystemJarNotPresentException.class, new Runnable() { 76 | @Override 77 | public void run() { 78 | SysOutOverSLF4J.systemOutputsAreSLF4JPrintStreams(); 79 | } 80 | }); 81 | 82 | assertEquals(SysOutOverSLF4JSystemJarNotPresentException.MESSAGE, exception.getMessage()); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /functional-tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | uk.org.lidalia.sysout-over-slf4j 5 | sysout-over-slf4j-parent 6 | 2.0.0-SNAPSHOT 7 | 8 | functional-tests 9 | pom 10 | Functional Tests 11 | Functional tests of sysout-over-slf4j in a variety of circumstances. 12 | 13 | no-system-jar-on-classpath 14 | sysout-over-slf4j-webapps 15 | tests 16 | 17 | 18 | -------------------------------------------------------------------------------- /functional-tests/sysout-over-slf4j-webapps/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 4.0.0 5 | 6 | uk.org.lidalia.sysout-over-slf4j 7 | functional-tests 8 | 2.0.0-SNAPSHOT 9 | 10 | sysout-over-slf4j-webapps 11 | pom 12 | Test Web Applications 13 | A collection of web applications using different logging implementations for 14 | functional testing of sysout-over-slf4j's behaviour when several reloadable contexts exist in a JVM. 15 | 16 | webapp-with-jdk14 17 | 18 | 19 | -------------------------------------------------------------------------------- /functional-tests/sysout-over-slf4j-webapps/webapp-with-jdk14/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | uk.org.lidalia.sysout-over-slf4j 5 | sysout-over-slf4j-webapps 6 | 2.0.0-SNAPSHOT 7 | 8 | webapp-with-jdk14 9 | war 10 | Webapp using java.util.logging 11 | A webapp configured to use java.util.logging as its logging implementation. 12 | 13 | 14 | org.slf4j 15 | slf4j-api 16 | 17 | 18 | org.slf4j 19 | slf4j-jdk14 20 | ${slf4j.version} 21 | runtime 22 | 23 | 24 | ${project.groupId} 25 | sysout-over-slf4j-context 26 | ${project.version} 27 | runtime 28 | 29 | 30 | ${project.groupId} 31 | sysout-over-slf4j-system 32 | ${project.version} 33 | provided 34 | 35 | 36 | javax 37 | javaee-web-api 38 | 39 | 40 | com.google.guava 41 | guava 42 | 43 | 44 | uk.org.lidalia 45 | lidalia-lang 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /functional-tests/sysout-over-slf4j-webapps/webapp-with-jdk14/src/main/java/uk/org/lidalia/sysoutslf4j/webapps/LoggerServlet.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j.webapps; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServlet; 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import static com.google.common.base.Optional.fromNullable; 14 | 15 | public class LoggerServlet extends HttpServlet { 16 | 17 | private static final long serialVersionUID = 1; 18 | 19 | @Override 20 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 21 | String loggerName = fromNullable(request.getParameter("logger")).or(Logger.ROOT_LOGGER_NAME); 22 | boolean useNative = Boolean.valueOf(request.getParameter("native")); 23 | String message = request.getParameter("message"); 24 | if (useNative) { 25 | java.util.logging.Logger.getLogger(loggerName).info(message); 26 | } else { 27 | LoggerFactory.getLogger(loggerName).info(message); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /functional-tests/sysout-over-slf4j-webapps/webapp-with-jdk14/src/main/java/uk/org/lidalia/sysoutslf4j/webapps/LoggingFilter.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j.webapps; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.Filter; 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.FilterConfig; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.ServletRequest; 10 | import javax.servlet.ServletResponse; 11 | import javax.servlet.http.HttpServletRequest; 12 | 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import static uk.org.lidalia.lang.Exceptions.throwUnchecked; 17 | 18 | public class LoggingFilter implements Filter { 19 | 20 | private static final Logger LOG = LoggerFactory.getLogger(LoggingFilter.class); 21 | 22 | @Override 23 | public void init(FilterConfig filterConfig) throws ServletException { 24 | // Nothing to do 25 | } 26 | 27 | @Override 28 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 29 | try { 30 | filterChain.doFilter(servletRequest, servletResponse); 31 | } catch (Throwable t) { 32 | LOG.error("Uncaught exception handling request " + requestLine((HttpServletRequest) servletRequest), t); 33 | throwUnchecked(t); 34 | } 35 | } 36 | 37 | private String requestLine(HttpServletRequest httpRequest) { 38 | final StringBuffer requestURL = httpRequest.getRequestURL(); 39 | final String queryString = httpRequest.getQueryString(); 40 | if (queryString != null && queryString.length() > 0) { 41 | requestURL.append('?').append(queryString); 42 | } 43 | return httpRequest.getMethod() + " " + requestURL; 44 | } 45 | 46 | @Override 47 | public void destroy() { 48 | // Nothing to do 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /functional-tests/sysout-over-slf4j-webapps/webapp-with-jdk14/src/main/java/uk/org/lidalia/sysoutslf4j/webapps/PrinterServlet.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j.webapps; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServlet; 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | 10 | import uk.org.lidalia.sysoutslf4j.system.SystemOutput; 11 | 12 | import static com.google.common.base.Optional.fromNullable; 13 | 14 | public class PrinterServlet extends HttpServlet { 15 | 16 | private static final long serialVersionUID = 1; 17 | 18 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 19 | String name = fromNullable(request.getParameter("output")).or("System.out"); 20 | SystemOutput output = SystemOutput.findByName(name); 21 | output.get().println(request.getParameter("message")); 22 | } 23 | 24 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /functional-tests/sysout-over-slf4j-webapps/webapp-with-jdk14/src/main/webapp/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Class-Path: 3 | 4 | -------------------------------------------------------------------------------- /functional-tests/sysout-over-slf4j-webapps/webapp-with-jdk14/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | Webapp With JDK14 7 | 8 | 9 | uk.org.lidalia.sysoutslf4j.context.ServletContextListener 10 | 11 | 12 | 13 | logger 14 | uk.org.lidalia.sysoutslf4j.webapps.LoggerServlet 15 | 16 | 17 | logger 18 | /log 19 | 20 | 21 | printer 22 | uk.org.lidalia.sysoutslf4j.webapps.PrinterServlet 23 | 24 | 25 | printer 26 | /print 27 | 28 | 29 | -------------------------------------------------------------------------------- /functional-tests/tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | functional-tests 7 | uk.org.lidalia.sysout-over-slf4j 8 | 2.0.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | tests 13 | pom 14 | Tests 15 | 16 | 17 | ${project.groupId} 18 | webapp-with-jdk14 19 | ${project.version} 20 | war 21 | 22 | 23 | ${project.groupId} 24 | sysout-over-slf4j-system 25 | ${project.version} 26 | 27 | 28 | 29 | 30 | 31 | org.apache.maven.plugins 32 | maven-surefire-plugin 33 | 34 | true 35 | 36 | 37 | 38 | org.apache.maven.plugins 39 | maven-failsafe-plugin 40 | 41 | 42 | org.codehaus.cargo 43 | cargo-maven2-plugin 44 | 45 | 46 | 47 | 8081 48 | 49 | 50 | 51 | 52 | ${project.groupId} 53 | webapp-with-jdk14 54 | war 55 | 56 | /webapp-with-jdk14 57 | 58 | 59 | 60 | 61 | 62 | 63 | start-container 64 | pre-integration-test 65 | 66 | start 67 | 68 | 69 | 70 | stop-container 71 | post-integration-test 72 | 73 | stop 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 4.0.0 5 | 6 | 7 | uk.org.lidalia 8 | parent 9 | 1.3.0 10 | 11 | 12 | uk.org.lidalia.sysout-over-slf4j 13 | sysout-over-slf4j-parent 14 | 2.0.0-SNAPSHOT 15 | pom 16 | 17 | System Out and Err redirected to SLF4J 18 | http://projects.lidalia.org.uk/sysout-over-slf4j/ 19 | Library to send raw System.out and System.err output to SLF4J for proper logging control 20 | 21 | 22 | 23 | github 24 | file:///tmp/${project.name} 25 | 26 | 27 | 28 | 29 | sysout-over-slf4j-context 30 | sysout-over-slf4j-system 31 | functional-tests 32 | 33 | 34 | 35 | GitHub Issues 36 | https://github.com/Mahoney/sysout-over-slf4j/issues 37 | 38 | 39 | 40 | 41 | Robert Elliot 42 | rob@lidalia.org.uk 43 | 44 | 45 | 46 | 47 | 48 | MIT X11 License 49 | file://${project.basedir}/LICENSE.txt 50 | repo 51 | 52 | 53 | 54 | 55 | scm:git:git@github.com:Mahoney/sysout-over-slf4j.git 56 | scm:git:git@github.com:Mahoney/sysout-over-slf4j.git 57 | https://github.com/Mahoney/sysout-over-slf4j 58 | 59 | 60 | 61 | 62 | slf4j-announcements list 63 | http://www.qos.ch/mailman/listinfo/announce 64 | http://www.qos.ch/mailman/options/announce 65 | http://www.qos.ch/pipermail/announce/ 66 | 67 | http://marc.theaimsgroup.com/?l=slf4j-announce 68 | 69 | 70 | 71 | slf4j-user list 72 | http://www.qos.ch/mailman/listinfo/slf4j-user 73 | http://www.qos.ch/mailman/options/slf4j-user 74 | slf4j-user@qos.ch 75 | http://www.qos.ch/pipermail/slf4j-user/ 76 | 77 | http://news.gmane.org/gmane.comp.java.slf4j.user 78 | http://marc.theaimsgroup.com/?l=slf4j-user 79 | http://www.nabble.com/Slf4J---user-f13203.html 80 | http://www.mail-archive.com/user%40slf4j.org/ 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | uk.org.lidalia 89 | lidalia-test-dependencies 90 | 1.1.0 91 | pom 92 | test 93 | 94 | 95 | commons-io 96 | commons-io 97 | ${commons-io.version} 98 | 99 | 100 | ch.qos.logback 101 | logback-core 102 | ${logback.version} 103 | 104 | 105 | uk.org.lidalia 106 | lidalia-lang 107 | 1.0.0 108 | 109 | 110 | uk.org.lidalia 111 | lidalia-slf4j-ext 112 | 1.0.0 113 | 114 | 115 | javax.servlet 116 | servlet-api 117 | 2.3 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /src/site/apt/index.apt.vm: -------------------------------------------------------------------------------- 1 | System Out and Err Redirected to SLF4J 2 | 3 | The ${project.artifactId} module allows a user to redirect all calls to 4 | System.out and System.err to an SLF4J defined logger with the name of 5 | the fully qualified class in which the System.out.println (or similar) 6 | call was made, at configurable levels. 7 | 8 | *What are the intended use cases? 9 | 10 | The ${project.artifactId} module is for cases where your legacy codebase, 11 | or a third party module you use, prints directly to the console and 12 | you would like to get the benefits of a proper logging framework, 13 | with automatic capture of information like timestamp and the ability 14 | to filter which messages you are interested in seeing and control where 15 | they are sent. 16 | 17 | The ${project.artifactId} module is explicitly not intended to encourage 18 | the use of System.out or System.err for logging purposes. There is a 19 | significant performance overhead attached to its use, and as such it 20 | should be considered a stop-gap for your own code until you can alter 21 | it to use SLF4J directly, or a work-around for poorly behaving third 22 | party modules. 23 | 24 | *Getting started 25 | 26 | Follow the {{{quickstart.html}Quick start}} guide. 27 | -------------------------------------------------------------------------------- /src/site/apt/quickstart.apt.vm: -------------------------------------------------------------------------------- 1 | Quick Start 2 | 3 | *Add ${project.artifactId} to the classpath 4 | 5 | Download the ${project.artifactId}-${project.version}.jar on the {{{http://github.com/Mahoney/sysout-over-slf4j/downloads}Downloads page}}. 6 | 7 | Alternatively, add the following to your maven pom dependencies: 8 | 9 | ---------------------------------------- 10 | 11 | ${project.groupId} 12 | ${project.artifactId} 13 | ${project.version} 14 | 15 | ---------------------------------------- 16 | 17 | *In a Standalone Application 18 | 19 | Make the following call as early as possible in the startup of your application: 20 | 21 | ---------------------------------------- 22 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); 23 | ---------------------------------------- 24 | 25 | *In a Servlet Container 26 | 27 | Add the following to your web.xml: 28 | 29 | ---------------------------------------- 30 | 31 | uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4JServletContextListener 32 | 33 | ---------------------------------------- 34 | -------------------------------------------------------------------------------- /src/site/fml/faq.fml.vm: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | General 10 | 11 | 12 | 13 | Help - I'm getting a StackOverFlowError every time I log or println! 14 | 15 | 16 |

You are probably using an SLF4J implementation that tries to write to the console using one of the print(ln) methods 17 | on PrintStream. These are in turn redirected back to your SLF4J implementation by ${project.artifactId}, resulting in an 18 | infinite loop. To prevent this, add the following call early in the lifecycle of your application:

19 | 20 | SysOutOverSLF4J.registerLoggingSystem("package.of.slf4j.implementation"); 21 | 22 |

${project.artifactId} will then recognise all attempts to write to system out or err from your logging system and will 23 | delegate them to the original system out or err PrintStream.

24 | 25 |

Note that you should ONLY register a logging system if you need to - many logging systems (including Logback, Log4J and 26 | JULI) use the write methods on PrintStream, which always delegate directly to the original PrintStream, and so do not have 27 | this problem.

28 |
29 |
30 | 31 | 32 | 33 | What if I want System.out calls to log as debug rather than info? 34 | Or System.err calls to log as warn rather than error? 35 | 36 | 37 |

You can customise the levels at which ${project.artifactId} logs when initially configuring it at application startup. 38 | Simply call:

39 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(Level.DEBUG, Level.WARN); 40 |

instead of the no argument version. The first argument represents the level of calls to System.out, and the 41 | second argument represents the level of calls to System.err.

42 |
43 |
44 | 45 | 46 | 47 | Why does ${project.artifactId} log a separate log statement for every element in the stack in a stacktrace? 48 | 49 | 50 |

When Throwable.printStackTrace() is called it iterates over the frames in the Throwable's stack trace and 51 | prints each to the System.err as a separate method call. This leaves no reliable means of reconstituting the 52 | original Throwable, or recognising the last frame of the stack trace. Whilst logging each frame separately is 53 | clearly sub-optimal, it is at present the only known way of reliably retaining all the information from a 54 | printStackTrace call and maintaining its ordering.

55 |

In recognition that this is unsatisfactory ${project.artifactId} allows you to substitute in your own exception 56 | handling mechanism by implementing ExceptionHandlingStrategyFactory and passing an instance of your implementation 57 | in when configuring ${project.artifactId} at startup:

58 | ExceptionHandlingStrategyFactory factory = new CustomExceptionHandlingStrategyFactory(); 59 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(factory); 60 |
61 |
62 | 63 | 64 | 65 | Don't most logging systems print to the console? Won't that mean infinite recursion? 66 | 67 | 68 |

As mentioned above, the most common SLF4J implementations use the write methods on PrintStream, which always delegate 69 | directly to the original PrintStream, and so are not affected by use of sysout-over-slf4j.

70 |
71 |
72 | 73 | 74 | What are the performance implications of using sysout-over-slf4j? 75 | 76 | 77 |

The overhead for Log4J, JULI and Logback when printing to the 78 | console should be minimal, because SLF4J simply proxies calls to 79 | the write methods through to the original PrintStreams without 80 | doing any work.

81 | 82 |

The overhead for some other SLF4J implementation that does not use the PrintStream write methods, and so needs to be 83 | registered, will be greater; on every attempt by it to print to the console its fully qualified class name has to be 84 | matched against registered package names in order to determine whether it should be permitted direct access.

85 | 86 |

Finally, the overhead of actual System.out and System.err calls will be much greater, due to the expense of generating 87 | the thread's stacktrace and examining it to determine the origin of the call. It would be much better 88 | if all logging were done via SLF4J directly and this module were not necessary.

89 |
90 |
91 | 92 | 93 | 94 | How does it work? 95 | 96 | 97 |

The System.out and System.err PrintStreams are replaced with 98 | new SLF4JPrintStreams. Each time a call to System.out.println (or 99 | similar) is made, the current thread's stacktrace is examined to 100 | determine which class made the call. An SLF4J Logger named after 101 | that class's fully qualified name is retrieved and the message 102 | logged at the configured level on that logger (by default info for 103 | System.out calls and error for System.err calls).

104 | 105 |

Calls to Throwable.printStackTrace() are likewise logged at 106 | the configured level for each System output. By default there 107 | will be a message logged for every line of the stack trace; this 108 | is an unfortunate side effect of not being able to 109 | retrieve the original exception that is being printed reliably.

110 | 111 |

A servlet container may contain multiple web applications. 112 | If it has child first class loading and these applications 113 | package SLF4J in the web-app/lib directory then there will be 114 | multiple SLF4J instances running in the JVM. However, there 115 | is only one System.out and one System.err for the whole JVM. 116 | In order to ensure that the correct SLF4J instance is used 117 | for the correct web application, inside the new PrintStreams 118 | SLF4J instances are mapped against the context 119 | class loader to ensure that the same SLF4J instance used in 120 | "normal" logging is also used when calling System.out.println.

121 | 122 |

In order to prevent class loader leaks when contexts 123 | are reloaded the new PrintStreams are created by a special 124 | class loader so that they do not themselves maintain a reference 125 | to the context class loader. The PrintStreams only maintain a weak 126 | reference to the class loaders and their SLF4J instances, so that 127 | no class loader leak occurs if the class loader is discarded.

128 |
129 |
130 | 131 |
132 |
133 | -------------------------------------------------------------------------------- /src/site/site.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 4.0.0 5 | 6 | 7 | uk.org.lidalia.sysout-over-slf4j 8 | sysout-over-slf4j-parent 9 | 2.0.0-SNAPSHOT 10 | 11 | sysout-over-slf4j-context 12 | 13 | Context Jar 14 | 15 | Contains the API for using sysout-over-slf4j and all the classes that can safely be loaded in the context of a classloader 16 | than can be discarded (such as a webapp in a servlet container). 17 | 18 | 19 | 20 | 21 | uk.org.lidalia 22 | lidalia-lang 23 | 24 | 25 | com.google.guava 26 | guava 27 | 28 | 29 | uk.org.lidalia 30 | lidalia-slf4j-ext 31 | 32 | 33 | 34 | 35 | ch.qos.logback 36 | logback-core 37 | compile 38 | true 39 | 40 | 41 | log4j 42 | log4j 43 | 1.2.13 44 | compile 45 | true 46 | 47 | 48 | 49 | 50 | javax.servlet 51 | servlet-api 52 | provided 53 | true 54 | 55 | 56 | ${project.groupId} 57 | sysout-over-slf4j-system 58 | ${project.version} 59 | provided 60 | 61 | 62 | 63 | 64 | uk.org.lidalia 65 | lidalia-test-dependencies 66 | pom 67 | 68 | 69 | commons-io 70 | commons-io 71 | test 72 | 73 | 74 | org.apache.commons 75 | commons-lang3 76 | test 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/.gitignore: -------------------------------------------------------------------------------- 1 | /resources 2 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/CallOrigin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context; 26 | 27 | import com.google.common.base.Optional; 28 | import com.google.common.base.Supplier; 29 | import uk.org.lidalia.sysoutslf4j.system.PerContextPrintStream; 30 | 31 | import java.util.List; 32 | 33 | import static java.util.Arrays.asList; 34 | 35 | final class CallOrigin { 36 | 37 | private static final Supplier THROW_ILLEGAL_STATE_EXCEPTION = new Supplier() { 38 | @Override 39 | public Integer get() { 40 | throw new IllegalStateException("Must be called from down stack of " + PerContextPrintStream.class.getName()); 41 | } 42 | }; 43 | private final boolean printingStackTrace; 44 | private final String className; 45 | private final boolean inLoggingSystem; 46 | 47 | private CallOrigin(final boolean isStacktrace, final boolean inLoggingSystem, final String className) { 48 | this.printingStackTrace = isStacktrace; 49 | this.className = className; 50 | this.inLoggingSystem = inLoggingSystem; 51 | } 52 | 53 | boolean isPrintingStackTrace() { 54 | return printingStackTrace; 55 | } 56 | 57 | String getClassName() { 58 | return className; 59 | } 60 | 61 | boolean isInLoggingSystem() { 62 | return inLoggingSystem; 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return "CallOrigin{" + 68 | "printingStackTrace=" + printingStackTrace + 69 | ", className='" + className + '\'' + 70 | ", inLoggingSystem=" + inLoggingSystem + 71 | '}'; 72 | } 73 | 74 | static CallOrigin getCallOrigin(LoggingSystemRegister loggingSystemRegister) { 75 | Thread currentThread = Thread.currentThread(); 76 | final List stackTraceElements = asList(currentThread.getStackTrace()); 77 | int firstPerContextPrintStreamFrame = frameWithPrintStreamClassName(stackTraceElements, 0).or(THROW_ILLEGAL_STATE_EXCEPTION); 78 | int secondPerContextPrintStreamFrame = frameWithPrintStreamClassName(stackTraceElements, firstPerContextPrintStreamFrame + 1).or(stackTraceElements.size()); 79 | 80 | final List interestingStackTraceElements = stackTraceElements.subList(firstPerContextPrintStreamFrame + 1, secondPerContextPrintStreamFrame); 81 | 82 | for (int i = interestingStackTraceElements.size() - 2; i >= 0; i--) { 83 | StackTraceElement stackTraceElement = interestingStackTraceElements.get(i); 84 | String currentClassName = stackTraceElement.getClassName(); 85 | if (currentClassName.equals(Throwable.class.getName()) && stackTraceElement.getMethodName().equals("printStackTrace")) { 86 | return new CallOrigin(true, false, getOuterClassName(interestingStackTraceElements.get(i + 1).getClassName())); 87 | } 88 | if (loggingSystemRegister.isInLoggingSystem(currentClassName)) { 89 | return new CallOrigin(false, true, null); 90 | } 91 | } 92 | return new CallOrigin(false, false, getOuterClassName(interestingStackTraceElements.get(0).getClassName())); 93 | } 94 | 95 | private static Optional frameWithPrintStreamClassName(final List stackTraceElements, int startPoint) { 96 | for (int i = startPoint; i < stackTraceElements.size(); i++) { 97 | StackTraceElement stackTraceElement = stackTraceElements.get(i); 98 | String currentClassName = stackTraceElement.getClassName(); 99 | if (currentClassName.equals(PerContextPrintStream.class.getName())) { 100 | return Optional.of(i); 101 | } 102 | } 103 | return Optional.absent(); 104 | } 105 | 106 | private static String getOuterClassName(final String className) { 107 | final int startOfInnerClassName = className.indexOf('$'); 108 | final String outerClassName; 109 | if (startOfInnerClassName == -1) { 110 | outerClassName = className; 111 | } else { 112 | outerClassName = className.substring(0, startOfInnerClassName); 113 | } 114 | return outerClassName; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/LoggingMessages.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j.context; 2 | 3 | public final class LoggingMessages { 4 | public static final String PERFORMANCE_WARNING = "A logging system is sending data to the console. This will work but with a significant performance hit. " + 5 | "Visit http://projects.lidalia.org.uk/sysout-over-slf4j/performance.html for details of how to avoid this."; 6 | 7 | private LoggingMessages() { 8 | throw new UnsupportedOperationException("Not instantiable"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/LoggingOutputStream.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j.context; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.PrintStream; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | import java.util.concurrent.atomic.AtomicBoolean; 9 | 10 | import uk.org.lidalia.slf4jext.Level; 11 | import uk.org.lidalia.slf4jext.Logger; 12 | import uk.org.lidalia.slf4jext.LoggerFactory; 13 | import uk.org.lidalia.sysoutslf4j.context.exceptionhandlers.ExceptionHandlingStrategy; 14 | 15 | import static uk.org.lidalia.sysoutslf4j.context.CallOrigin.getCallOrigin; 16 | 17 | class LoggingOutputStream extends ByteArrayOutputStream { 18 | 19 | private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggingOutputStream.class); 20 | 21 | private final Level level; 22 | private final ExceptionHandlingStrategy exceptionHandlingStrategy; 23 | private final PrintStream originalPrintStream; 24 | private final LoggingSystemRegister loggingSystemRegister; 25 | 26 | LoggingOutputStream(final Level level, final ExceptionHandlingStrategy exceptionHandlingStrategy, 27 | final PrintStream originalPrintStream, final LoggingSystemRegister loggingSystemRegister) { 28 | super(); 29 | this.level = level; 30 | this.exceptionHandlingStrategy = exceptionHandlingStrategy; 31 | this.originalPrintStream = originalPrintStream; 32 | this.loggingSystemRegister = loggingSystemRegister; 33 | } 34 | 35 | @Override 36 | public synchronized void flush() throws IOException { 37 | final CallOrigin callOrigin = getCallOrigin(loggingSystemRegister); 38 | if (callOrigin.isInLoggingSystem()) { 39 | writeToOriginalPrintStream(); 40 | } else { 41 | String bufferAsString = new String(toByteArray()); 42 | if (bufferAsString.endsWith("\n")) { 43 | reset(); 44 | log(callOrigin, bufferAsString); 45 | } else if (bufferAsString.contains("\n")) { 46 | reset(); 47 | List messages = Arrays.asList(bufferAsString.split("\n")); 48 | List messagesToLog = messages.subList(0, messages.size() - 1); 49 | for (String messageToLog : messagesToLog) { 50 | log(callOrigin, messageToLog); 51 | } 52 | String lastMessage = messages.get(messages.size() - 1); 53 | write(lastMessage.getBytes()); 54 | } 55 | } 56 | } 57 | 58 | private void writeToOriginalPrintStream() throws IOException { 59 | exceptionHandlingStrategy.notifyNotStackTrace(); 60 | warnAboutPerformance(); 61 | writeTo(originalPrintStream); 62 | originalPrintStream.flush(); 63 | reset(); 64 | } 65 | 66 | private static final AtomicBoolean warned = new AtomicBoolean(false); 67 | 68 | private static void warnAboutPerformance() { 69 | if (warned.compareAndSet(false, true)) { 70 | log.warn(LoggingMessages.PERFORMANCE_WARNING); 71 | } 72 | } 73 | 74 | private void log(final CallOrigin callOrigin, String bufferAsString) { 75 | String valueToLog = StringUtils.stripEnd(bufferAsString, " \r\n"); 76 | try { 77 | if (valueToLog.length() > 0) { 78 | if (callOrigin.isPrintingStackTrace()) { 79 | exceptionHandlingStrategy.handleExceptionLine(valueToLog, org.slf4j.LoggerFactory.getLogger(callOrigin.getClassName())); 80 | } else { 81 | exceptionHandlingStrategy.notifyNotStackTrace(); 82 | LoggerFactory.getLogger(callOrigin.getClassName()).log(level, valueToLog); 83 | } 84 | } 85 | } catch (StackOverflowError stackOverflowError) { 86 | throw new IllegalStateException("Logging system " + org.slf4j.LoggerFactory.getLogger(Object.class).getClass() + 87 | " is sending data to the console - please register it by calling SysOutOverSLF4J.registerLoggingSystem. " + 88 | "Original message: " + System.getProperty("line.separator") + valueToLog, stackOverflowError); 89 | } 90 | } 91 | 92 | protected void finalize() throws Throwable { 93 | super.finalize(); 94 | String bufferAsString = StringUtils.stripEnd(new String(toByteArray()), " \r\n"); 95 | if (bufferAsString.length() > 0) { 96 | Logger logger = LoggerFactory.getLogger(SysOutOverSLF4J.class); 97 | logger.log(level, bufferAsString); 98 | } 99 | reset(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/LoggingSystemRegister.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context; 26 | 27 | import java.util.Set; 28 | import java.util.concurrent.CopyOnWriteArraySet; 29 | 30 | import org.slf4j.Logger; 31 | import org.slf4j.LoggerFactory; 32 | 33 | import static java.util.Arrays.asList; 34 | 35 | class LoggingSystemRegister { 36 | 37 | private static final Logger LOG = LoggerFactory.getLogger(SysOutOverSLF4J.class); 38 | private final Set loggingSystemNameFragments = new CopyOnWriteArraySet(asList( 39 | "org.x4juli.", 40 | "org.grlea.log.", 41 | "org.slf4j.impl.SimpleLogger", 42 | "ch.qos.logback.", 43 | "org.slf4j.impl.Log4jLoggerAdapter", 44 | "org.slf4j.impl.JDK14LoggerAdapter", 45 | "org.apache.log4j.", 46 | "java.util.logging.", 47 | "uk.org.lidalia.slf4jtest.")); 48 | 49 | void registerLoggingSystem(final String packageName) { 50 | loggingSystemNameFragments.add(packageName); 51 | LOG.info("Package {} registered; all classes within it or subpackages of it will " + 52 | "be allowed to print to System.out and System.err", packageName); 53 | } 54 | 55 | void unregisterLoggingSystem(final String packageName) { 56 | if (loggingSystemNameFragments.remove(packageName)) { 57 | LOG.info("Package {} unregistered; all classes within it or subpackages of it will " + 58 | "have System.out and System.err redirected to SLF4J", packageName); 59 | } 60 | } 61 | 62 | boolean isInLoggingSystem(final String className) { 63 | for (String packageName : loggingSystemNameFragments) { 64 | if (className.startsWith(packageName)) { 65 | return true; 66 | } 67 | } 68 | return false; 69 | } 70 | 71 | LoggingSystemRegister() { 72 | super(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/ReferenceHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context; 26 | 27 | import java.util.Collections; 28 | import java.util.IdentityHashMap; 29 | import java.util.Map; 30 | 31 | final class ReferenceHolder { 32 | 33 | private static final Map REFERENCES = Collections.synchronizedMap(new IdentityHashMap()); 34 | 35 | static void preventGarbageCollectionForLifeOfClassLoader(final Object objectToBeMaintained) { 36 | REFERENCES.put(objectToBeMaintained, objectToBeMaintained); 37 | } 38 | 39 | static void allowGarbageCollection(final Object objectBeingMaintained) { 40 | REFERENCES.remove(objectBeingMaintained); 41 | } 42 | 43 | private ReferenceHolder() { 44 | throw new UnsupportedOperationException("Not instantiable"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/ServletContextListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context; 26 | 27 | import javax.servlet.ServletContextEvent; 28 | 29 | import org.slf4j.Logger; 30 | import org.slf4j.LoggerFactory; 31 | 32 | public class ServletContextListener implements javax.servlet.ServletContextListener { 33 | 34 | private static final Logger LOG = LoggerFactory.getLogger(ServletContextListener.class); 35 | 36 | public final void contextInitialized(final ServletContextEvent servletContextEvent) { 37 | try { 38 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); 39 | } catch (SysOutOverSLF4JSystemJarNotPresentException e) { 40 | LOG.warn("You do not have sysout-over-slf4j-system on your classpath - it is required for redirecting system outputs to SLF4J.", e); 41 | } 42 | } 43 | 44 | public void contextDestroyed(final ServletContextEvent servletContextEvent) { 45 | try { 46 | SysOutOverSLF4J.stopSendingSystemOutAndErrToSLF4J(); 47 | } catch (SysOutOverSLF4JSystemJarNotPresentException e) { 48 | LOG.debug("You do not have sysout-over-slf4j-system on your classpath - it is required for redirecting system outputs to SLF4J.", e); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/StringUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context; 26 | 27 | final class StringUtils { 28 | 29 | static String stripEnd(final String str, final String stripChars) { 30 | return stripEnd(str, str.length() - 1, stripChars); 31 | } 32 | 33 | private static String stripEnd(final String string, final int index, final String stripChars) { 34 | final String result; 35 | if (index == -1) { 36 | result = ""; 37 | } else { 38 | final char candidateToBeStripped = string.charAt(index); 39 | final boolean candidateShouldNotBeStripped = stripChars.indexOf(candidateToBeStripped) == -1; 40 | if (candidateShouldNotBeStripped) { 41 | result = string.substring(0, index + 1); 42 | } else { 43 | result = stripEnd(string, index - 1, stripChars); 44 | } 45 | } 46 | return result; 47 | } 48 | 49 | private StringUtils() { 50 | throw new UnsupportedOperationException("Not instantiable"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/SysOutOverSLF4JSystemJarNotPresentException.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j.context; 2 | 3 | public class SysOutOverSLF4JSystemJarNotPresentException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public static final String MESSAGE = 8 | "You do not seem to have sysout-over-slf4j-system on your classpath. In order to redirect system outputs to slf4j " + 9 | "it is necessary to add this jar to your classpath, at a point where it is visible to all class loaders and " + 10 | "where the class loader that will load it will never be discarded."; 11 | 12 | public SysOutOverSLF4JSystemJarNotPresentException(Throwable cause) { 13 | super(MESSAGE, cause); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/exceptionhandlers/ExceptionHandlingStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context.exceptionhandlers; 26 | 27 | import org.slf4j.Logger; 28 | 29 | /** 30 | * This interface defines the methods used by sysout-over-slf4j to convert the results of Throwable.printStacktrace 31 | * into logging events.
32 | * 33 | * Since the exception itself cannot be reclaimed, all that is available is the individual lines of the stack trace 34 | * as they are printed to System.out/err. Something more like normal logging might be achievable by buffering these 35 | * lines and constructing a new Exception from them. 36 | * 37 | */ 38 | public interface ExceptionHandlingStrategy { 39 | 40 | /** 41 | * Called for each line of the stack trace as sent to the System.out/err PrintStream. 42 | * 43 | * @param line The stacktrace line 44 | * @param log The {@link org.slf4j.Logger} with a name matching the fully qualified name of the 45 | * class where printStacktrace was called 46 | */ 47 | void handleExceptionLine(String line, Logger log); 48 | 49 | /** 50 | * Called whenever any other calls are intercepted by sysout-over-slf4j 51 | * - may be a useful trigger for flushing a buffer. 52 | */ 53 | void notifyNotStackTrace(); 54 | } 55 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/exceptionhandlers/ExceptionHandlingStrategyFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context.exceptionhandlers; 26 | 27 | import java.io.PrintStream; 28 | 29 | import uk.org.lidalia.slf4jext.Level; 30 | 31 | /** 32 | *

33 | * Interface for factories that create ExceptionHandlingStrategies to allow users to provide their own mechanism 34 | * for handling the difficult problem of capturing the output of Throwable.printStacktrace() and turning it into 35 | * logging events. 36 | *

37 | * 38 | *

39 | * The default implementation is {@link LogPerLineExceptionHandlingStrategyFactory} which returns an 40 | * {@link ExceptionHandlingStrategy} that simply logs each line of the stack trace as a separate logging event. 41 | *

42 | */ 43 | public interface ExceptionHandlingStrategyFactory { 44 | 45 | /** 46 | * This method will be called twice for each context that is sent to SLF4J, once each to return an 47 | * {@link ExceptionHandlingStrategy} for the new System.out and System.err print streams.
48 | * 49 | * It is called with the {@link Level} of the SLF4JPrintStream and the original System output 50 | * PrintStream that is being replaced, so that ExceptionHandlingStrategies can have direct access to 51 | * the console if they wish. 52 | * 53 | * @param logLevel The {@link Level} of the parent PrintStream (by default INFO for System.out 54 | * and ERROR for System.err) 55 | * @param originalPrintStream The original System output PrintStream providing direct access to the console 56 | * @return an {@link ExceptionHandlingStrategy} that will be called with each line of an Exception that is 57 | * printed using Throwable.printStacktrace() or Throwable.printStacktrace(System.out) 58 | */ 59 | ExceptionHandlingStrategy makeExceptionHandlingStrategy(Level logLevel, PrintStream originalPrintStream); 60 | 61 | } 62 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/exceptionhandlers/LogPerLineExceptionHandlingStrategyFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context.exceptionhandlers; 26 | 27 | import java.io.PrintStream; 28 | 29 | import org.slf4j.Marker; 30 | import org.slf4j.MarkerFactory; 31 | 32 | import uk.org.lidalia.slf4jext.Level; 33 | import uk.org.lidalia.slf4jext.Logger; 34 | 35 | /** 36 | * Implementation of {@link LogPerLineExceptionHandlingStrategyFactory} which returns an 37 | * {@link ExceptionHandlingStrategy} that simply logs each line of the stack trace as a separate logging event. 38 | */ 39 | public final class LogPerLineExceptionHandlingStrategyFactory implements ExceptionHandlingStrategyFactory { 40 | 41 | private static final ExceptionHandlingStrategyFactory INSTANCE = new LogPerLineExceptionHandlingStrategyFactory(); 42 | public static ExceptionHandlingStrategyFactory getInstance() { 43 | return INSTANCE; 44 | } 45 | 46 | private LogPerLineExceptionHandlingStrategyFactory() { 47 | super(); 48 | } 49 | 50 | public ExceptionHandlingStrategy makeExceptionHandlingStrategy( 51 | final Level logLevel, final PrintStream originalPrintStream) { 52 | return new LogPerLineExceptionHandlingStrategy(logLevel); 53 | } 54 | 55 | private static final class LogPerLineExceptionHandlingStrategy implements ExceptionHandlingStrategy { 56 | 57 | private static final Marker MARKER = MarkerFactory.getMarker("stacktrace"); 58 | 59 | private final Level logLevel; 60 | 61 | LogPerLineExceptionHandlingStrategy(final Level logLevel) { 62 | super(); 63 | this.logLevel = logLevel; 64 | } 65 | 66 | /** 67 | * This method is not used since nothing is buffered. 68 | */ 69 | public void notifyNotStackTrace() { 70 | // Do nothing 71 | } 72 | 73 | public void handleExceptionLine(final String line, final org.slf4j.Logger log) { 74 | new Logger(log).log(logLevel, MARKER, line); 75 | } 76 | 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/jul/ConsoleHandler.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j.context.jul; 2 | 3 | import java.util.logging.LogRecord; 4 | import java.util.logging.StreamHandler; 5 | 6 | import uk.org.lidalia.sysoutslf4j.system.PerContextSystemOutput; 7 | 8 | public class ConsoleHandler extends StreamHandler { 9 | 10 | /** 11 | * Create a ConsoleHandler for System.err. 12 | *

13 | * The ConsoleHandler is configured based on 14 | * LogManager properties (or their default values). 15 | * 16 | */ 17 | public ConsoleHandler() { 18 | setOutputStream(PerContextSystemOutput.ERR.getOriginalPrintStream()); 19 | } 20 | 21 | /** 22 | * Publish a LogRecord. 23 | *

24 | * The logging request was made initially to a Logger object, 25 | * which initialized the LogRecord and forwarded it here. 26 | *

27 | * @param record description of the log event. A null record is 28 | * silently ignored and is not published 29 | */ 30 | public void publish(LogRecord record) { 31 | super.publish(record); 32 | flush(); 33 | } 34 | 35 | /** 36 | * Override StreamHandler.close to do a flush but not 37 | * to close the output stream. That is, we do not 38 | * close System.err. 39 | */ 40 | public void close() { 41 | flush(); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/log4j/ConsoleAppender.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j.context.log4j; 2 | 3 | import org.apache.log4j.Layout; 4 | import org.apache.log4j.WriterAppender; 5 | import org.apache.log4j.helpers.LogLog; 6 | 7 | import uk.org.lidalia.sysoutslf4j.system.PerContextSystemOutput; 8 | 9 | public class ConsoleAppender extends WriterAppender { 10 | 11 | public static final String SYSTEM_OUT = "System.out"; 12 | public static final String SYSTEM_ERR = "System.err"; 13 | 14 | protected String target = SYSTEM_OUT; 15 | 16 | /** 17 | * Constructs an unconfigured appender. 18 | */ 19 | public ConsoleAppender() { 20 | } 21 | 22 | /** 23 | * Creates a configured appender. 24 | * 25 | * @param layout layout, may not be null. 26 | */ 27 | public ConsoleAppender(Layout layout) { 28 | this(layout, SYSTEM_OUT); 29 | } 30 | 31 | /** 32 | * Creates a configured appender. 33 | * @param layout layout, may not be null. 34 | * @param target target, either "System.err" or "System.out". 35 | */ 36 | public ConsoleAppender(Layout layout, String target) { 37 | setLayout(layout); 38 | setTarget(target); 39 | activateOptions(); 40 | } 41 | 42 | /** 43 | * Sets the value of the Target option. Recognized values 44 | * are "System.out" and "System.err". Any other value will be 45 | * ignored. 46 | * */ 47 | public void setTarget(String value) { 48 | String v = value.trim(); 49 | 50 | if (SYSTEM_OUT.equalsIgnoreCase(v)) { 51 | target = SYSTEM_OUT; 52 | } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { 53 | target = SYSTEM_ERR; 54 | } else { 55 | targetWarn(value); 56 | } 57 | } 58 | 59 | /** 60 | * Returns the current value of the Target property. The 61 | * default value of the option is "System.out". 62 | * 63 | * See also {@link #setTarget}. 64 | * */ 65 | public String getTarget() { 66 | return target; 67 | } 68 | 69 | void targetWarn(String val) { 70 | LogLog.warn("["+val+"] should be System.out or System.err."); 71 | LogLog.warn("Using previously set target, System.out by default."); 72 | } 73 | 74 | /** 75 | * Prepares the appender for use. 76 | */ 77 | public void activateOptions() { 78 | if (target.equals(SYSTEM_ERR)) { 79 | setWriter(createWriter(PerContextSystemOutput.ERR.getOriginalPrintStream())); 80 | } else { 81 | setWriter(createWriter(PerContextSystemOutput.OUT.getOriginalPrintStream())); 82 | } 83 | super.activateOptions(); 84 | } 85 | 86 | @Override 87 | protected final void closeWriter() { 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/main/java/uk/org/lidalia/sysoutslf4j/context/logback/ConsoleAppender.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j.context.logback; 2 | 3 | import java.util.Arrays; 4 | 5 | import ch.qos.logback.core.OutputStreamAppender; 6 | import ch.qos.logback.core.status.Status; 7 | import ch.qos.logback.core.status.WarnStatus; 8 | 9 | import uk.org.lidalia.sysoutslf4j.system.PerContextSystemOutput; 10 | import uk.org.lidalia.sysoutslf4j.system.SystemOutput; 11 | 12 | public final class ConsoleAppender extends OutputStreamAppender { 13 | 14 | private PerContextSystemOutput target = PerContextSystemOutput.OUT; 15 | 16 | /** 17 | * Sets the value of the Target option. Recognized values are 18 | * "System.out" and "System.err". Any other value will be ignored. 19 | */ 20 | public void setTarget(String value) { 21 | PerContextSystemOutput t = PerContextSystemOutput.findByName(value.trim()); 22 | if (t == null) { 23 | targetWarn(value); 24 | } else { 25 | target = t; 26 | } 27 | } 28 | 29 | private void targetWarn(String val) { 30 | Status status = new WarnStatus("[" + val + "] should be one of " 31 | + Arrays.toString(SystemOutput.values()), this); 32 | status.add(new WarnStatus("Using previously set target, System.out by default.", this)); 33 | addStatus(status); 34 | } 35 | 36 | @Override 37 | public void start() { 38 | setOutputStream(target.getOriginalPrintStream()); 39 | super.start(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/.gitignore: -------------------------------------------------------------------------------- 1 | /resources 2 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/SysOutOverSLF4JTestCase.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j; 2 | 3 | import java.io.PrintStream; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | 8 | import uk.org.lidalia.slf4jtest.TestLoggerFactory; 9 | 10 | /* 11 | * Copyright (c) 2009-2012 Robert Elliot 12 | * All rights reserved. 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | public abstract class SysOutOverSLF4JTestCase { 35 | 36 | protected ClassLoader originalContextClassLoader; 37 | protected PrintStream SYS_OUT; 38 | protected PrintStream SYS_ERR; 39 | 40 | @Before 41 | public void resetLoggers() { 42 | TestLoggerFactory.clearAll(); 43 | } 44 | 45 | @Before 46 | public void storeOriginalSystemOutAndErr() { 47 | SYS_OUT = System.out; 48 | SYS_ERR = System.err; 49 | } 50 | 51 | @After 52 | public void restoreOriginalSystemOutAndErr() { 53 | System.setOut(SYS_OUT); 54 | System.setErr(SYS_ERR); 55 | } 56 | 57 | @Before 58 | public void storeOriginalContextClassLoader() { 59 | originalContextClassLoader = Thread.currentThread().getContextClassLoader(); 60 | } 61 | 62 | @After 63 | public void restoreOriginalContextClassLoader() { 64 | Thread.currentThread().setContextClassLoader(originalContextClassLoader); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/context/CallOriginTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context; 26 | 27 | import org.junit.Test; 28 | import org.junit.runner.RunWith; 29 | import org.powermock.core.classloader.annotations.PrepareForTest; 30 | import org.powermock.modules.junit4.PowerMockRunner; 31 | 32 | import uk.org.lidalia.sysoutslf4j.system.PerContextPrintStream; 33 | 34 | import static org.junit.Assert.assertEquals; 35 | import static org.junit.Assert.assertFalse; 36 | import static org.junit.Assert.assertTrue; 37 | import static org.powermock.api.mockito.PowerMockito.mock; 38 | import static org.powermock.api.mockito.PowerMockito.mockStatic; 39 | import static org.powermock.api.mockito.PowerMockito.when; 40 | import static uk.org.lidalia.test.ShouldThrow.shouldThrow; 41 | 42 | @RunWith(PowerMockRunner.class) 43 | @PrepareForTest({CallOrigin.class, LoggingSystemRegister.class}) 44 | public class CallOriginTests { 45 | 46 | private final LoggingSystemRegister loggingSystemRegister = mock(LoggingSystemRegister.class); 47 | @Test 48 | public void getCallOriginThrowsIllegalStateExceptionIfNoPerContextPrintStreamStackEntry() { 49 | expectGetStackTraceToReturn( 50 | stackTraceElement("org.a.1"), 51 | stackTraceElement("org.a.2"), 52 | stackTraceElement("main.Class") 53 | ); 54 | 55 | IllegalStateException exception = shouldThrow(IllegalStateException.class, new Runnable() { 56 | public void run() { 57 | CallOrigin.getCallOrigin(loggingSystemRegister); 58 | } 59 | }); 60 | assertEquals("Must be called from down stack of uk.org.lidalia.sysoutslf4j.system.PerContextPrintStream", exception.getMessage()); 61 | } 62 | 63 | @Test 64 | public void getCallOriginReturnsFirstClassName() { 65 | expectGetStackTraceToReturn( 66 | stackTraceElement(PerContextPrintStream.class), 67 | stackTraceElement("org.a.ClassName"), 68 | stackTraceElement("org.b.ClassName"), 69 | stackTraceElement("main.Class") 70 | ); 71 | 72 | CallOrigin callOrigin = CallOrigin.getCallOrigin(loggingSystemRegister); 73 | assertEquals("org.a.ClassName", callOrigin.getClassName()); 74 | } 75 | 76 | @Test 77 | public void getCallOriginIsNotStackTraceIfThrowableNotFirstElement() { 78 | expectGetStackTraceToReturn( 79 | stackTraceElement(PerContextPrintStream.class), 80 | stackTraceElement("org.a.ClassName"), 81 | stackTraceElement("main.Class") 82 | ); 83 | 84 | CallOrigin callOrigin = CallOrigin.getCallOrigin(loggingSystemRegister); 85 | assertFalse(callOrigin.toString(), callOrigin.isPrintingStackTrace()); 86 | } 87 | 88 | @Test 89 | public void getCallOriginIsStackTraceIfThrowableIsInStackBeforePerContextPrintStreamElement() { 90 | expectGetStackTraceToReturn( 91 | stackTraceElement(PerContextPrintStream.class), 92 | stackTraceElement("java.lang.Throwable", "printStackTrace"), 93 | stackTraceElement("org.a.ClassName"), 94 | stackTraceElement("main.Class") 95 | ); 96 | 97 | CallOrigin callOrigin = CallOrigin.getCallOrigin(loggingSystemRegister); 98 | assertTrue(callOrigin.toString(), callOrigin.isPrintingStackTrace()); 99 | } 100 | 101 | @Test 102 | public void getCallOriginReturnsFirstClassNameOtherThanThrowable() { 103 | expectGetStackTraceToReturn( 104 | stackTraceElement(PerContextPrintStream.class), 105 | stackTraceElement("some.other.ClassName"), 106 | stackTraceElement(Throwable.class, "printStackTrace"), 107 | stackTraceElement("org.a.ClassName"), 108 | stackTraceElement("main.Class") 109 | ); 110 | 111 | CallOrigin callOrigin = CallOrigin.getCallOrigin(loggingSystemRegister); 112 | assertEquals("org.a.ClassName", callOrigin.getClassName()); 113 | } 114 | 115 | @Test 116 | public void getCallOriginReturnsInnerClassesAsTheOuterClass() { 117 | expectGetStackTraceToReturn( 118 | stackTraceElement(PerContextPrintStream.class), 119 | stackTraceElement("org.a.ClassName$InnerClass"), 120 | stackTraceElement("org.b.ClassName"), 121 | stackTraceElement("main.Class") 122 | ); 123 | CallOrigin callOrigin = CallOrigin.getCallOrigin(loggingSystemRegister); 124 | assertEquals("org.a.ClassName", callOrigin.getClassName()); 125 | } 126 | 127 | @Test 128 | public void getCallOriginIsInLoggingSystemIfLoggingSystemRegisterSaysItIs() { 129 | expectGetStackTraceToReturn( 130 | stackTraceElement(PerContextPrintStream.class), 131 | stackTraceElement(Throwable.class, "printStackTrace"), 132 | stackTraceElement("class.in.logging.system"), 133 | stackTraceElement("main.Class") 134 | ); 135 | when(loggingSystemRegister.isInLoggingSystem("class.in.logging.system")).thenReturn(true); 136 | 137 | CallOrigin callOrigin = CallOrigin.getCallOrigin(loggingSystemRegister); 138 | assertTrue(callOrigin.toString(), callOrigin.isInLoggingSystem()); 139 | } 140 | 141 | private void expectGetStackTraceToReturn(StackTraceElement... stackTraceElements) { 142 | Thread mockThread = mock(Thread.class); 143 | when(mockThread.getStackTrace()).thenReturn(stackTraceElements); 144 | mockStatic(Thread.class); 145 | when(Thread.currentThread()).thenReturn(mockThread); 146 | when(Thread.class.getName()).thenReturn("java.lang.Thread"); 147 | } 148 | 149 | private StackTraceElement stackTraceElement(Class declaringClass, String methodName) { 150 | return stackTraceElement(declaringClass.getName(), methodName); 151 | } 152 | 153 | private StackTraceElement stackTraceElement(String declaringClass, String methodName) { 154 | return new StackTraceElement(declaringClass, methodName, "", 0); 155 | } 156 | 157 | private StackTraceElement stackTraceElement(Class declaringClass) { 158 | return stackTraceElement(declaringClass, ""); 159 | } 160 | 161 | private StackTraceElement stackTraceElement(String declaringClass) { 162 | return stackTraceElement(declaringClass, ""); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/context/LoggingOutputStreamTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context; 26 | 27 | import java.io.PrintStream; 28 | import java.util.Arrays; 29 | import java.util.concurrent.atomic.AtomicBoolean; 30 | 31 | import org.junit.Before; 32 | import org.junit.Test; 33 | import org.junit.runner.RunWith; 34 | import org.powermock.core.classloader.annotations.PrepareForTest; 35 | import org.powermock.modules.junit4.PowerMockRunner; 36 | import org.powermock.reflect.Whitebox; 37 | import org.slf4j.Logger; 38 | 39 | import uk.org.lidalia.slf4jtest.TestLogger; 40 | import uk.org.lidalia.slf4jtest.TestLoggerFactory; 41 | import uk.org.lidalia.slf4jext.Level; 42 | import uk.org.lidalia.sysoutslf4j.SysOutOverSLF4JTestCase; 43 | import uk.org.lidalia.sysoutslf4j.context.exceptionhandlers.ExceptionHandlingStrategy; 44 | 45 | import static java.util.Arrays.asList; 46 | import static java.util.Collections.emptyList; 47 | import static org.junit.Assert.assertEquals; 48 | import static org.mockito.Matchers.any; 49 | import static org.mockito.Matchers.anyString; 50 | import static org.mockito.Mockito.never; 51 | import static org.mockito.Mockito.verify; 52 | import static org.powermock.api.mockito.PowerMockito.mock; 53 | import static org.powermock.api.mockito.PowerMockito.mockStatic; 54 | import static org.powermock.api.mockito.PowerMockito.when; 55 | import static uk.org.lidalia.slf4jtest.LoggingEvent.info; 56 | import static uk.org.lidalia.slf4jtest.LoggingEvent.warn; 57 | 58 | @RunWith(PowerMockRunner.class) 59 | @PrepareForTest({CallOrigin.class, LoggingSystemRegister.class}) 60 | public class LoggingOutputStreamTests extends SysOutOverSLF4JTestCase { 61 | 62 | private static final String CLASS_IN_LOGGING_SYSTEM = "org.logging.LoggerClass"; 63 | private static final String CLASS_NAME = "org.something.SomeClass"; 64 | 65 | private Level level = Level.INFO; 66 | 67 | private ExceptionHandlingStrategy exceptionHandlingStrategyMock = mock(ExceptionHandlingStrategy.class); 68 | private PrintStream origPrintStreamMock = mock(PrintStream.class); 69 | private LoggingSystemRegister loggingSystemRegisterMock = mock(LoggingSystemRegister.class); 70 | private LoggingOutputStream outputStream = new LoggingOutputStream(level, exceptionHandlingStrategyMock, origPrintStreamMock, loggingSystemRegisterMock); 71 | private TestLogger logger = TestLoggerFactory.getTestLogger(CLASS_NAME); 72 | 73 | @Before 74 | public void setUp() { 75 | mockGettingCallOrigin(false, false, CLASS_NAME); 76 | } 77 | 78 | @Test 79 | public void flushLogsWhenMessageEndsWithUnixLineBreak() throws Exception { 80 | outputStream.write("the message\n".getBytes("UTF-8")); 81 | outputStream.flush(); 82 | assertEquals(asList(info("the message")), logger.getLoggingEvents()); 83 | } 84 | 85 | @Test 86 | public void flushLogsWhenMessageEndsWithWindowsLineBreak() throws Exception { 87 | outputStream.write("the message\r\n".getBytes("UTF-8")); 88 | outputStream.flush(); 89 | assertEquals(asList(info("the message")), logger.getLoggingEvents()); 90 | } 91 | 92 | @Test 93 | public void flushWritesToOriginalPrintStreamIfInLoggingSystem() throws Exception { 94 | mockGettingCallOrigin(false, true, CLASS_IN_LOGGING_SYSTEM); 95 | 96 | byte[] bytes = "twelve chars".getBytes("UTF-8"); 97 | outputStream.write(bytes); 98 | outputStream.flush(); 99 | 100 | byte[] expected = Arrays.copyOf(bytes, 32); 101 | verify(origPrintStreamMock).write(expected, 0, 12); 102 | verify(exceptionHandlingStrategyMock).notifyNotStackTrace(); 103 | verify(exceptionHandlingStrategyMock, never()).handleExceptionLine(anyString(), any(Logger.class)); 104 | } 105 | 106 | @Test 107 | public void flushWarnsOnceIfInLoggingSystem() throws Exception { 108 | AtomicBoolean warned = (AtomicBoolean) Whitebox.getField(LoggingOutputStream.class, "warned").get(LoggingOutputStream.class); 109 | warned.set(false); 110 | mockGettingCallOrigin(false, true, CLASS_IN_LOGGING_SYSTEM); 111 | 112 | byte[] bytes = "twelve chars".getBytes("UTF-8"); 113 | outputStream.write(bytes); 114 | outputStream.flush(); 115 | outputStream.write(bytes); 116 | outputStream.flush(); 117 | 118 | TestLogger loggingOutputStreamLogger = TestLoggerFactory.getTestLogger(LoggingOutputStream.class); 119 | assertEquals(asList(warn(LoggingMessages.PERFORMANCE_WARNING)), loggingOutputStreamLogger.getLoggingEvents()); 120 | } 121 | 122 | @Test 123 | public void flushNonStackTraceNotifiesNotStackTrace() throws Exception { 124 | outputStream.write("some text\n".getBytes("UTF-8")); 125 | outputStream.flush(); 126 | verify(exceptionHandlingStrategyMock).notifyNotStackTrace(); 127 | verify(exceptionHandlingStrategyMock, never()).handleExceptionLine(anyString(), any(Logger.class)); 128 | } 129 | 130 | @Test 131 | public void flushStackTraceCallsExceptionHandlingStrategy() throws Exception { 132 | mockGettingCallOrigin(true, false, CLASS_NAME); 133 | 134 | outputStream.write("exception line\n".getBytes("UTF-8")); 135 | outputStream.flush(); 136 | 137 | verify(exceptionHandlingStrategyMock).handleExceptionLine("exception line", logger); 138 | verify(exceptionHandlingStrategyMock, never()).notifyNotStackTrace(); 139 | assertEquals(emptyList(), logger.getLoggingEvents()); 140 | } 141 | 142 | @Test 143 | public void flushResetsBuffer() throws Exception { 144 | outputStream.write("1".getBytes("UTF-8")); 145 | outputStream.write("2\n".getBytes("UTF-8")); 146 | outputStream.flush(); 147 | 148 | assertEquals(asList(info("12")), logger.getLoggingEvents()); 149 | 150 | outputStream.write("3".getBytes("UTF-8")); 151 | outputStream.write("4\n".getBytes("UTF-8")); 152 | outputStream.flush(); 153 | 154 | assertEquals(asList(info("12"), info("34")), logger.getLoggingEvents()); 155 | } 156 | 157 | private void mockGettingCallOrigin(boolean isStackTrace, boolean inLoggingSystem, String className) { 158 | CallOrigin callOriginMock = mock(CallOrigin.class); 159 | when(callOriginMock.isPrintingStackTrace()).thenReturn(isStackTrace); 160 | when(callOriginMock.getClassName()).thenReturn(className); 161 | when(callOriginMock.isInLoggingSystem()).thenReturn(inLoggingSystem); 162 | 163 | mockStatic(CallOrigin.class); 164 | when(CallOrigin.getCallOrigin(loggingSystemRegisterMock)).thenReturn(callOriginMock); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/context/LoggingSystemRegisterTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context; 26 | 27 | import java.util.Set; 28 | 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | import org.junit.runner.RunWith; 32 | import org.powermock.core.classloader.annotations.PrepareForTest; 33 | import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; 34 | import org.powermock.modules.junit4.PowerMockRunner; 35 | import org.powermock.reflect.Whitebox; 36 | import org.slf4j.Logger; 37 | 38 | import static org.junit.Assert.assertFalse; 39 | import static org.junit.Assert.assertTrue; 40 | import static org.mockito.Mockito.verify; 41 | import static org.powermock.api.mockito.PowerMockito.mock; 42 | import static org.powermock.api.mockito.PowerMockito.verifyZeroInteractions; 43 | 44 | @RunWith(PowerMockRunner.class) 45 | @PrepareForTest({ LoggingSystemRegister.class }) 46 | @SuppressStaticInitializationFor("uk.org.lidalia.sysoutslf4j.context.LoggingSystemRegister") 47 | public class LoggingSystemRegisterTests { 48 | 49 | private LoggingSystemRegister loggingSystemRegister = new LoggingSystemRegister(); 50 | private Logger loggerMock = mock(Logger.class); 51 | 52 | @Before 53 | public void setStaticMocks() { 54 | Whitebox.setInternalState(LoggingSystemRegister.class, loggerMock); 55 | } 56 | 57 | @Test 58 | public void isInLoggingSystemReturnsFalseWhenLoggingSystemNotRegistered() { 59 | assertFalse(loggingSystemRegister.isInLoggingSystem("some.package.SomeClass")); 60 | } 61 | 62 | @Test 63 | public void registerLoggingSystemRegistersALoggingSystem() { 64 | loggingSystemRegister.registerLoggingSystem("some.package"); 65 | assertTrue(loggingSystemRegister.isInLoggingSystem("some.package.SomeClass")); 66 | } 67 | 68 | @Test 69 | public void unregisterLoggingSystemUnregistersALoggingSystem() { 70 | loggingSystemRegister.registerLoggingSystem("some.package"); 71 | loggingSystemRegister.unregisterLoggingSystem("some.package"); 72 | assertFalse(loggingSystemRegister.isInLoggingSystem("some.package.SomeClass")); 73 | } 74 | 75 | @Test 76 | public void registerLoggingSystemLogsThatItWasRegistered() { 77 | loggingSystemRegister.registerLoggingSystem("some.package"); 78 | verify(loggerMock).info("Package {} registered; all classes within it or subpackages of it will " 79 | + "be allowed to print to System.out and System.err", "some.package"); 80 | } 81 | 82 | @SuppressWarnings("unchecked") 83 | @Test 84 | public void unregisterLoggingSystemLogsThatItWasUnregisteredIfLoggingSystemRegistered() { 85 | Whitebox.getInternalState(loggingSystemRegister, Set.class).add("some.package"); 86 | 87 | loggingSystemRegister.unregisterLoggingSystem("some.package"); 88 | 89 | verify(loggerMock).info("Package {} unregistered; all classes within it or subpackages of it will " 90 | + "have System.out and System.err redirected to SLF4J", "some.package"); 91 | } 92 | 93 | @Test 94 | public void unregisterLoggingSystemDoesNotLogIfLoggingSystemNotRegisterdPresent() { 95 | loggingSystemRegister.unregisterLoggingSystem("some.package"); 96 | verifyZeroInteractions(loggerMock); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/context/ReferenceHolderTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context; 26 | 27 | import java.lang.ref.WeakReference; 28 | 29 | import org.junit.Test; 30 | 31 | import static org.junit.Assert.assertNotNull; 32 | import static org.junit.Assert.assertNull; 33 | import static org.junit.Assert.assertThat; 34 | import static uk.org.lidalia.test.Assert.isNotInstantiable; 35 | 36 | public class ReferenceHolderTests { 37 | 38 | @Test 39 | public void preventGarbageCollectionForLifeOfClassLoaderMaintainsInstance() { 40 | Object object = new Object(); 41 | WeakReference ref = new WeakReference(object); 42 | 43 | ReferenceHolder.preventGarbageCollectionForLifeOfClassLoader(object); 44 | object = null; 45 | System.gc(); 46 | 47 | assertNotNull(ref.get()); 48 | } 49 | 50 | @Test 51 | public void allowGarbageCollectionForLifeOfClassLoaderFreesUpInstance() { 52 | Object object = new Object(); 53 | WeakReference ref = new WeakReference(object); 54 | 55 | ReferenceHolder.preventGarbageCollectionForLifeOfClassLoader(object); 56 | ReferenceHolder.allowGarbageCollection(object); 57 | object = null; 58 | System.gc(); 59 | 60 | assertNull(ref.get()); 61 | } 62 | 63 | @Test 64 | public void notInstantiable() throws Throwable { 65 | assertThat(ReferenceHolder.class, isNotInstantiable()); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/context/ServletContextListenerTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context; 26 | 27 | import org.junit.Test; 28 | import org.junit.runner.RunWith; 29 | import org.powermock.core.classloader.annotations.PrepareForTest; 30 | import org.powermock.modules.junit4.PowerMockRunner; 31 | 32 | import uk.org.lidalia.sysoutslf4j.SysOutOverSLF4JTestCase; 33 | 34 | import static org.powermock.api.mockito.PowerMockito.mockStatic; 35 | import static org.powermock.api.mockito.PowerMockito.verifyStatic; 36 | 37 | @RunWith(PowerMockRunner.class) 38 | @PrepareForTest({ SysOutOverSLF4J.class }) 39 | public class ServletContextListenerTests extends SysOutOverSLF4JTestCase { 40 | 41 | private ServletContextListener servletContextListener = new ServletContextListener(); 42 | 43 | @Test 44 | public void testContextInitializedCallsSendSystemOutAndErrToSLF4J() { 45 | mockStatic(SysOutOverSLF4J.class); 46 | 47 | servletContextListener.contextInitialized(null); 48 | 49 | verifyStatic(); 50 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); 51 | } 52 | 53 | @Test 54 | public void testContextDestroyedDoesNothing() { 55 | mockStatic(SysOutOverSLF4J.class); 56 | 57 | servletContextListener.contextDestroyed(null); 58 | 59 | verifyStatic(); 60 | SysOutOverSLF4J.stopSendingSystemOutAndErrToSLF4J(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/context/StringUtilsTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context; 26 | 27 | import org.junit.Test; 28 | 29 | import uk.org.lidalia.sysoutslf4j.SysOutOverSLF4JTestCase; 30 | 31 | import static org.junit.Assert.assertEquals; 32 | import static org.junit.Assert.assertThat; 33 | import static uk.org.lidalia.test.Assert.isNotInstantiable; 34 | import static uk.org.lidalia.test.ShouldThrow.shouldThrow; 35 | 36 | public class StringUtilsTests extends SysOutOverSLF4JTestCase { 37 | 38 | @Test 39 | public void stripEndStripsEnd() { 40 | assertEquals("hello wo", StringUtils.stripEnd("hello world", "elders")); 41 | } 42 | 43 | @Test 44 | public void stripEndReturnsEmptyStringIfEmptyStringPassedIn() { 45 | assertEquals("", StringUtils.stripEnd("", "irrelevant")); 46 | } 47 | 48 | @Test 49 | public void stripEndReturnsInputIfEmptyStripCharsPassedIn() { 50 | assertEquals("hello", StringUtils.stripEnd("hello", "")); 51 | } 52 | 53 | @Test 54 | public void stripEndThrowsNullPointerExceptionIfInputIsNull() { 55 | shouldThrow(NullPointerException.class, new Runnable() { 56 | public void run() { 57 | StringUtils.stripEnd(null, "irrelevant"); 58 | } 59 | }); 60 | } 61 | 62 | @Test 63 | public void stripEndThrowsNullPointerExceptionIfStripCharsIsNull() { 64 | shouldThrow(NullPointerException.class, new Runnable() { 65 | public void run() { 66 | StringUtils.stripEnd("irrelevant", null); 67 | } 68 | }); 69 | } 70 | 71 | @Test 72 | public void notInstantiable() { 73 | assertThat(StringUtils.class, isNotInstantiable()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/context/SysOutOverSLF4JNotInstantiableTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j.context; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertThat; 6 | import static uk.org.lidalia.test.Assert.isNotInstantiable; 7 | 8 | public class SysOutOverSLF4JNotInstantiableTest { 9 | 10 | @Test 11 | public void notInstantiable() throws Throwable { 12 | assertThat(SysOutOverSLF4J.class, isNotInstantiable()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/context/SysOutOverSLF4JTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context; 26 | 27 | import java.io.PrintStream; 28 | 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | import org.junit.runner.RunWith; 32 | import org.powermock.core.classloader.annotations.PrepareForTest; 33 | import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; 34 | import org.powermock.modules.junit4.PowerMockRunner; 35 | import org.powermock.reflect.Whitebox; 36 | import org.slf4j.Logger; 37 | 38 | import uk.org.lidalia.slf4jext.Level; 39 | import uk.org.lidalia.sysoutslf4j.SysOutOverSLF4JTestCase; 40 | import uk.org.lidalia.sysoutslf4j.context.exceptionhandlers.ExceptionHandlingStrategy; 41 | import uk.org.lidalia.sysoutslf4j.context.exceptionhandlers.ExceptionHandlingStrategyFactory; 42 | import uk.org.lidalia.sysoutslf4j.context.exceptionhandlers.LogPerLineExceptionHandlingStrategyFactory; 43 | import uk.org.lidalia.sysoutslf4j.system.PerContextSystemOutput; 44 | 45 | import static org.junit.Assert.assertFalse; 46 | import static org.junit.Assert.assertTrue; 47 | import static org.mockito.Mockito.verify; 48 | import static org.powermock.api.mockito.PowerMockito.mock; 49 | import static org.powermock.api.mockito.PowerMockito.mockStatic; 50 | import static org.powermock.api.mockito.PowerMockito.when; 51 | import static org.powermock.api.mockito.PowerMockito.whenNew; 52 | 53 | @RunWith(PowerMockRunner.class) 54 | @SuppressStaticInitializationFor("uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J") 55 | @PrepareForTest({ LogPerLineExceptionHandlingStrategyFactory.class, LoggingSystemRegister.class, PerContextSystemOutput.class }) 56 | public class SysOutOverSLF4JTests extends SysOutOverSLF4JTestCase { 57 | 58 | private final LoggingSystemRegister loggingSystemRegisterMock = mock(LoggingSystemRegister.class); 59 | private final Logger loggerMock = mock(Logger.class); 60 | private final PerContextSystemOutput outMock = mock(PerContextSystemOutput.class); 61 | private final PerContextSystemOutput errMock = mock(PerContextSystemOutput.class); 62 | private final ExceptionHandlingStrategyFactory customExceptionHandlingStrategyFactoryMock = mock(ExceptionHandlingStrategyFactory.class); 63 | private final ExceptionHandlingStrategyFactory defaultExceptionHandlingStrategyFactoryMock = mock(ExceptionHandlingStrategyFactory.class); 64 | 65 | private PrintStream outContextPrintStream; 66 | private PrintStream errContextPrintStream; 67 | 68 | @Before 69 | public void mockLoggingSystemRegister() { 70 | Whitebox.setInternalState(SysOutOverSLF4J.class, loggerMock); 71 | Whitebox.setInternalState(SysOutOverSLF4J.class, loggingSystemRegisterMock); 72 | } 73 | 74 | @Before 75 | public void mockLogPerLineExceptionHandlingStrategyFactory() { 76 | mockStatic(LogPerLineExceptionHandlingStrategyFactory.class); 77 | when(LogPerLineExceptionHandlingStrategyFactory.getInstance()).thenReturn(defaultExceptionHandlingStrategyFactoryMock); 78 | } 79 | 80 | @Before 81 | public void mockPerContextSystemOutputEnum() { 82 | Whitebox.setInternalState(PerContextSystemOutput.class, "OUT", outMock); 83 | Whitebox.setInternalState(PerContextSystemOutput.class, "ERR", errMock); 84 | mockStatic(PerContextSystemOutput.class); 85 | when(PerContextSystemOutput.values()).thenReturn(new PerContextSystemOutput[]{outMock, errMock}); 86 | } 87 | 88 | @Test 89 | public void sendSystemOutAndErrToSLF4JDelegatesToSLF4JPrintStreamManagerWithDefaultLevelsAndLogPerLineExceptionHandlingStrategy() throws Exception { 90 | expectLoggerAppendersToBeRegistered(Level.INFO, Level.ERROR, LogPerLineExceptionHandlingStrategyFactory.getInstance()); 91 | 92 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); 93 | 94 | verify(outMock).registerPrintStreamForThisContext(outContextPrintStream); 95 | verify(errMock).registerPrintStreamForThisContext(errContextPrintStream); 96 | } 97 | 98 | @Test 99 | public void sendSystemOutAndErrToSLF4JDelegatesToSLF4JPrintStreamManagerWithDefaultLevelsAndGivenExceptionHandlingStrategy() throws Exception { 100 | expectLoggerAppendersToBeRegistered(Level.INFO, Level.ERROR, customExceptionHandlingStrategyFactoryMock); 101 | 102 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(customExceptionHandlingStrategyFactoryMock); 103 | 104 | verify(outMock).registerPrintStreamForThisContext(outContextPrintStream); 105 | verify(errMock).registerPrintStreamForThisContext(errContextPrintStream); 106 | } 107 | 108 | @Test 109 | public void sendSystemOutAndErrToSLF4JDelegatesToSLF4JPrintStreamManagerWithCustomLevelsAndLogPerLineExceptionHandlingStrategy() throws Exception { 110 | expectLoggerAppendersToBeRegistered(Level.DEBUG, Level.WARN, LogPerLineExceptionHandlingStrategyFactory.getInstance()); 111 | 112 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(Level.DEBUG, Level.WARN); 113 | 114 | verify(outMock).registerPrintStreamForThisContext(outContextPrintStream); 115 | verify(errMock).registerPrintStreamForThisContext(errContextPrintStream); 116 | } 117 | 118 | @Test 119 | public void sendSystemOutAndErrToSLF4JDelegatesToSLF4JPrintStreamManagerWithCustomLevelsAndGivenExceptionHandlingStrategy() throws Exception { 120 | expectLoggerAppendersToBeRegistered(Level.DEBUG, Level.WARN, customExceptionHandlingStrategyFactoryMock); 121 | 122 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(Level.DEBUG, Level.WARN, customExceptionHandlingStrategyFactoryMock); 123 | 124 | verify(outMock).registerPrintStreamForThisContext(outContextPrintStream); 125 | verify(errMock).registerPrintStreamForThisContext(errContextPrintStream); 126 | } 127 | 128 | private void expectLoggerAppendersToBeRegistered(Level outLevel, Level errLevel, ExceptionHandlingStrategyFactory exceptionHandlingStrategyFactory) throws Exception { 129 | outContextPrintStream = expectLoggerAppenderToBeRegistered(outMock, outLevel, exceptionHandlingStrategyFactory); 130 | errContextPrintStream = expectLoggerAppenderToBeRegistered(errMock, errLevel, exceptionHandlingStrategyFactory); 131 | } 132 | 133 | private PrintStream expectLoggerAppenderToBeRegistered(PerContextSystemOutput systemOutputMock, Level logLevel, ExceptionHandlingStrategyFactory exceptionHandlingStrategyFactory) throws Exception { 134 | PrintStream originalPrintStreamMock = mock(PrintStream.class); 135 | when(systemOutputMock.getOriginalPrintStream()).thenReturn(originalPrintStreamMock); 136 | 137 | ExceptionHandlingStrategy exceptionHandlingStrategy = mock(ExceptionHandlingStrategy.class); 138 | when(exceptionHandlingStrategyFactory.makeExceptionHandlingStrategy(logLevel, originalPrintStreamMock)).thenReturn(exceptionHandlingStrategy); 139 | 140 | LoggingOutputStream slf4jOutputStreamMock = mock(LoggingOutputStream.class); 141 | whenNew(LoggingOutputStream.class).withArguments(logLevel, exceptionHandlingStrategy, originalPrintStreamMock, loggingSystemRegisterMock).thenReturn(slf4jOutputStreamMock); 142 | 143 | PrintStream newPrintStream = mock(PrintStream.class); 144 | whenNew(PrintStream.class).withArguments(slf4jOutputStreamMock, true).thenReturn(newPrintStream); 145 | 146 | return newPrintStream; 147 | } 148 | 149 | @Test 150 | public void stopSendingSystemOutAndErrToSLF4JDelegatesToSLF4JPrintStreamManager() { 151 | SysOutOverSLF4J.stopSendingSystemOutAndErrToSLF4J(); 152 | 153 | verify(outMock).deregisterPrintStreamForThisContext(); 154 | verify(errMock).deregisterPrintStreamForThisContext(); 155 | } 156 | 157 | @Test 158 | public void restoreOriginalSystemOutputsDelegatesToSLF4JPrintStreamManager() { 159 | SysOutOverSLF4J.restoreOriginalSystemOutputs(); 160 | 161 | verify(outMock).restoreOriginalPrintStream(); 162 | verify(errMock).restoreOriginalPrintStream(); 163 | } 164 | 165 | @Test 166 | public void registerLoggingSystemDelegatesToLoggingSystemRegister() { 167 | SysOutOverSLF4J.registerLoggingSystem("somePackageName"); 168 | verify(loggingSystemRegisterMock).registerLoggingSystem("somePackageName"); 169 | } 170 | 171 | @Test 172 | public void unregisterLoggingSystemDelegatesToLoggingSystemRegister() { 173 | SysOutOverSLF4J.unregisterLoggingSystem("somePackageName"); 174 | verify(loggingSystemRegisterMock).unregisterLoggingSystem("somePackageName"); 175 | } 176 | 177 | @Test 178 | public void isInLoggingSystemDelegatesToLoggingSystemRegister() { 179 | when(loggingSystemRegisterMock.isInLoggingSystem("somePackageName")).thenReturn(true); 180 | assertTrue(SysOutOverSLF4J.isInLoggingSystem("somePackageName")); 181 | 182 | when(loggingSystemRegisterMock.isInLoggingSystem("somePackageName")).thenReturn(false); 183 | assertFalse(SysOutOverSLF4J.isInLoggingSystem("somePackageName")); 184 | } 185 | 186 | @Test 187 | public void isSLF4JPrintStreamReturnsFalseWhenSystemOutIsSLF4JPrintStream() { 188 | when(outMock.isPerContextPrintStream()).thenReturn(false); 189 | assertFalse(SysOutOverSLF4J.systemOutputsAreSLF4JPrintStreams()); 190 | } 191 | 192 | @Test 193 | public void isSLF4JPrintStreamReturnsTrueWhenSystemOutIsSLF4JPrintStream() { 194 | when(outMock.isPerContextPrintStream()).thenReturn(true); 195 | assertTrue(SysOutOverSLF4J.systemOutputsAreSLF4JPrintStreams()); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/context/exceptionhandlers/TestLogPerLineExceptionHandlingStrategyFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context.exceptionhandlers; 26 | 27 | import org.junit.Test; 28 | import org.slf4j.Marker; 29 | import org.slf4j.MarkerFactory; 30 | 31 | import uk.org.lidalia.slf4jtest.TestLogger; 32 | import uk.org.lidalia.slf4jtest.TestLoggerFactory; 33 | import uk.org.lidalia.sysoutslf4j.SysOutOverSLF4JTestCase; 34 | import uk.org.lidalia.slf4jext.Level; 35 | 36 | import static java.util.Arrays.asList; 37 | import static org.junit.Assert.assertEquals; 38 | import static uk.org.lidalia.slf4jtest.LoggingEvent.error; 39 | import static uk.org.lidalia.slf4jtest.LoggingEvent.info; 40 | 41 | public class TestLogPerLineExceptionHandlingStrategyFactory extends SysOutOverSLF4JTestCase { 42 | 43 | private static final ExceptionHandlingStrategyFactory STRATEGY_FACTORY = 44 | LogPerLineExceptionHandlingStrategyFactory.getInstance(); 45 | private static final String EXCEPTION_LINE = "an exception line"; 46 | private static final Marker STACKTRACE = MarkerFactory.getMarker("stacktrace"); 47 | 48 | private TestLogger log = TestLoggerFactory.getTestLogger(TestLogPerLineExceptionHandlingStrategyFactory.class); 49 | 50 | @Test 51 | public void testHandleExceptionLineDelegatesToLoggerAtInfoLevel() { 52 | ExceptionHandlingStrategy strategy = STRATEGY_FACTORY.makeExceptionHandlingStrategy(Level.INFO, null); 53 | strategy.handleExceptionLine(EXCEPTION_LINE, log); 54 | assertEquals(asList(info(STACKTRACE, EXCEPTION_LINE)), log.getLoggingEvents()); 55 | } 56 | 57 | @Test 58 | public void testHandleExceptionLineDelegatesToLoggerAtErrorLevel() { 59 | ExceptionHandlingStrategy strategy = STRATEGY_FACTORY.makeExceptionHandlingStrategy(Level.ERROR, null); 60 | strategy.handleExceptionLine(EXCEPTION_LINE, log); 61 | assertEquals(asList(error(STACKTRACE, EXCEPTION_LINE)), log.getLoggingEvents()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/context/jul/ConsoleHandlerTests.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j.context.jul; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.PrintStream; 5 | import java.util.Collection; 6 | import java.util.logging.Handler; 7 | import java.util.logging.Logger; 8 | 9 | import org.junit.Test; 10 | 11 | import uk.org.lidalia.slf4jtest.LoggingEvent; 12 | import uk.org.lidalia.slf4jtest.TestLoggerFactory; 13 | import uk.org.lidalia.sysoutslf4j.SysOutOverSLF4JTestCase; 14 | import uk.org.lidalia.sysoutslf4j.context.LoggingMessages; 15 | import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J; 16 | import uk.org.lidalia.sysoutslf4j.system.SystemOutput; 17 | 18 | import static org.hamcrest.CoreMatchers.containsString; 19 | import static org.hamcrest.CoreMatchers.equalTo; 20 | import static org.hamcrest.CoreMatchers.not; 21 | import static org.hamcrest.MatcherAssert.assertThat; 22 | import static org.hamcrest.core.IsCollectionContaining.hasItem; 23 | import static uk.org.lidalia.slf4jtest.LoggingEvent.warn; 24 | 25 | public class ConsoleHandlerTests extends SysOutOverSLF4JTestCase { 26 | 27 | @Test 28 | public void appenderStillPrintsToSystemOut() { 29 | 30 | ByteArrayOutputStream outputStreamBytes = systemOutOutputStream(); 31 | 32 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); 33 | 34 | Logger log = Logger.getLogger(""); 35 | for (Handler handler : log.getHandlers()) { 36 | log.removeHandler(handler); 37 | } 38 | log.addHandler(new ConsoleHandler()); 39 | log.info("some log text"); 40 | 41 | String outString = new String(outputStreamBytes.toByteArray()); 42 | assertThat(outString, containsString("some log text")); 43 | 44 | Collection allLoggingEvents = TestLoggerFactory.getAllLoggingEvents(); 45 | assertThat(allLoggingEvents, not(hasItem(equalTo(warn(LoggingMessages.PERFORMANCE_WARNING))))); 46 | } 47 | 48 | ByteArrayOutputStream systemOutOutputStream() { 49 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 50 | PrintStream newSystemOut = new PrintStream(bytes, true); 51 | SystemOutput.ERR.set(newSystemOut); 52 | return bytes; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/context/log4j/ConsoleAppenderTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context.log4j; 26 | 27 | import java.io.ByteArrayOutputStream; 28 | import java.io.PrintStream; 29 | import java.util.Collection; 30 | 31 | import org.apache.log4j.Level; 32 | import org.apache.log4j.Logger; 33 | import org.apache.log4j.SimpleLayout; 34 | import org.junit.Test; 35 | 36 | import uk.org.lidalia.slf4jtest.LoggingEvent; 37 | import uk.org.lidalia.slf4jtest.TestLoggerFactory; 38 | import uk.org.lidalia.sysoutslf4j.SysOutOverSLF4JTestCase; 39 | import uk.org.lidalia.sysoutslf4j.context.LoggingMessages; 40 | import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J; 41 | import uk.org.lidalia.sysoutslf4j.system.SystemOutput; 42 | 43 | import static org.hamcrest.CoreMatchers.containsString; 44 | import static org.hamcrest.CoreMatchers.equalTo; 45 | import static org.hamcrest.CoreMatchers.not; 46 | import static org.hamcrest.MatcherAssert.assertThat; 47 | import static org.hamcrest.core.IsCollectionContaining.hasItem; 48 | import static uk.org.lidalia.slf4jtest.LoggingEvent.warn; 49 | 50 | public class ConsoleAppenderTests extends SysOutOverSLF4JTestCase { 51 | 52 | @Test 53 | public void appenderStillPrintsToSystemOut() { 54 | 55 | ByteArrayOutputStream outputStreamBytes = systemOutOutputStream(); 56 | 57 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); 58 | 59 | Logger log = Logger.getRootLogger(); 60 | log.setLevel(Level.INFO); 61 | log.removeAllAppenders(); 62 | log.addAppender(new ConsoleAppender(new SimpleLayout())); 63 | 64 | log.info("some log text"); 65 | 66 | String outString = new String(outputStreamBytes.toByteArray()); 67 | assertThat(outString, containsString("some log text")); 68 | 69 | Collection allLoggingEvents = TestLoggerFactory.getAllLoggingEvents(); 70 | assertThat(allLoggingEvents, not(hasItem(equalTo(warn(LoggingMessages.PERFORMANCE_WARNING))))); 71 | } 72 | 73 | ByteArrayOutputStream systemOutOutputStream() { 74 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 75 | PrintStream newSystemOut = new PrintStream(bytes, true); 76 | SystemOutput.OUT.set(newSystemOut); 77 | return bytes; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/context/logback/ConsoleAppenderTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.context.logback; 26 | 27 | import java.io.ByteArrayOutputStream; 28 | import java.io.PrintStream; 29 | import java.util.Collection; 30 | 31 | import org.junit.Test; 32 | 33 | import ch.qos.logback.core.ContextBase; 34 | import ch.qos.logback.core.encoder.EchoEncoder; 35 | import ch.qos.logback.core.encoder.Encoder; 36 | 37 | import uk.org.lidalia.slf4jtest.LoggingEvent; 38 | import uk.org.lidalia.slf4jtest.TestLoggerFactory; 39 | import uk.org.lidalia.sysoutslf4j.SysOutOverSLF4JTestCase; 40 | import uk.org.lidalia.sysoutslf4j.context.LoggingMessages; 41 | import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J; 42 | import uk.org.lidalia.sysoutslf4j.system.SystemOutput; 43 | 44 | import static org.hamcrest.CoreMatchers.containsString; 45 | import static org.hamcrest.CoreMatchers.equalTo; 46 | import static org.hamcrest.CoreMatchers.not; 47 | import static org.hamcrest.MatcherAssert.assertThat; 48 | import static org.hamcrest.core.IsCollectionContaining.hasItem; 49 | import static uk.org.lidalia.slf4jtest.LoggingEvent.warn; 50 | 51 | public class ConsoleAppenderTests extends SysOutOverSLF4JTestCase { 52 | 53 | @Test 54 | public void appenderStillPrintsToSystemOut() { 55 | 56 | ByteArrayOutputStream outputStreamBytes = systemOutOutputStream(); 57 | 58 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); 59 | 60 | ConsoleAppender consoleAppender = buildConsoleAppender(); 61 | consoleAppender.doAppend("some log text"); 62 | 63 | String outString = new String(outputStreamBytes.toByteArray()); 64 | assertThat(outString, containsString("some log text")); 65 | 66 | Collection allLoggingEvents = TestLoggerFactory.getAllLoggingEvents(); 67 | assertThat(allLoggingEvents, not(hasItem(equalTo(warn(LoggingMessages.PERFORMANCE_WARNING))))); 68 | } 69 | 70 | private ConsoleAppender buildConsoleAppender() { 71 | ConsoleAppender consoleAppender = new ConsoleAppender(); 72 | Encoder encoder = new EchoEncoder(); 73 | consoleAppender.setContext(new ContextBase()); 74 | consoleAppender.setEncoder(encoder); 75 | consoleAppender.start(); 76 | return consoleAppender; 77 | } 78 | 79 | private ByteArrayOutputStream systemOutOutputStream() { 80 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 81 | PrintStream newSystemOut = new PrintStream(bytes, true); 82 | SystemOutput.OUT.set(newSystemOut); 83 | return bytes; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/integration/CrossClassLoaderTestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.integration; 26 | 27 | import java.io.Serializable; 28 | import java.lang.reflect.InvocationHandler; 29 | import java.lang.reflect.Method; 30 | import java.lang.reflect.Modifier; 31 | import java.lang.reflect.Proxy; 32 | 33 | import org.apache.commons.lang3.SerializationUtils; 34 | 35 | import javassist.util.proxy.MethodHandler; 36 | import javassist.util.proxy.ProxyFactory; 37 | 38 | import uk.org.lidalia.lang.Exceptions; 39 | 40 | class CrossClassLoaderTestUtils { 41 | 42 | private static class ReflectionInvocationHandler implements MethodHandler, InvocationHandler { 43 | 44 | private final Object target; 45 | 46 | private ReflectionInvocationHandler(Object target) { 47 | this.target = target; 48 | } 49 | 50 | @Override 51 | public Object invoke(Object self, Method method, Method proceed, Object[] args) throws Throwable { 52 | return doWork(method, args); 53 | } 54 | 55 | @Override 56 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 57 | return doWork(method, args); 58 | } 59 | 60 | private Object doWork(Method method, Object[] args) throws Exception { 61 | args = args == null ? new Object[0] : args; 62 | Method targetMethod = target.getClass().getDeclaredMethod(method.getName(), method.getParameterTypes()); 63 | targetMethod.setAccessible(true); 64 | Object result = targetMethod.invoke(target, args); 65 | if (result == null) { 66 | return null; 67 | } 68 | Class resultClass = method.getReturnType(); 69 | if (resultClass.isPrimitive()) { 70 | return result; 71 | } else { 72 | String resultClassName = resultClass.getName(); 73 | Class resultClassLoadedInThisClassLoader = getClass().getClassLoader().loadClass(resultClassName); 74 | return moveToCurrentClassLoader(resultClassLoadedInThisClassLoader, result); 75 | } 76 | } 77 | } 78 | 79 | @SuppressWarnings("unchecked") 80 | public static E moveToCurrentClassLoader(Class destinationClass, Object target) { 81 | if (target.getClass().isPrimitive()) { 82 | return (E) target; 83 | } else if (destinationClass.isAssignableFrom(target.getClass())) { 84 | return (E) target; 85 | } else if (destinationClass.isInterface()) { 86 | return createProxyInterface(destinationClass, new ReflectionInvocationHandler(target)); 87 | } else if (target instanceof Enum) { 88 | return (E) getLocalEnumInstance((Enum) target, destinationClass); 89 | } else if (Modifier.isFinal(destinationClass.getModifiers())) { 90 | if (target instanceof Serializable) { 91 | return (E) moveToCurrentClassLoaderViaSerialization((Serializable) target); 92 | } else { 93 | return (E) target; 94 | } 95 | } else { 96 | return createProxyClass(destinationClass, new ReflectionInvocationHandler(target)); 97 | } 98 | } 99 | 100 | @SuppressWarnings({"unchecked", "rawtypes"}) 101 | private static Object getLocalEnumInstance(Enum enumInstance, Class destinationClass) { 102 | try { 103 | return Enum.valueOf(destinationClass, enumInstance.name()); 104 | } catch (Exception e) { 105 | Exceptions.throwUnchecked(e); 106 | throw new AssertionError("Unreachable"); 107 | } 108 | } 109 | 110 | @SuppressWarnings("unchecked") 111 | private static E createProxyInterface(Class classToProxy, ReflectionInvocationHandler handler) { 112 | return (E) Proxy.newProxyInstance(CrossClassLoaderTestUtils.class.getClassLoader(), new Class[] {classToProxy}, handler); 113 | } 114 | 115 | @SuppressWarnings("unchecked") 116 | private static E createProxyClass(Class classToProxy, ReflectionInvocationHandler handler) { 117 | ProxyFactory proxyFactory = new ProxyFactory(); 118 | proxyFactory.setSuperclass(classToProxy); 119 | try { 120 | return (E) proxyFactory.create(classToProxy.getDeclaredConstructors()[0].getParameterTypes(), new Object[classToProxy.getDeclaredConstructors()[0].getParameterTypes().length], handler); 121 | } catch (Exception e) { 122 | Exceptions.throwUnchecked(e); 123 | throw new AssertionError("Unreachable"); 124 | } 125 | } 126 | 127 | private static Object moveToCurrentClassLoaderViaSerialization(Serializable objectFromOtherClassLoader) { 128 | try { 129 | byte[] objectAsBytes = SerializationUtils.serialize(objectFromOtherClassLoader); 130 | return SerializationUtils.deserialize(objectAsBytes); 131 | } catch (Exception e) { 132 | Exceptions.throwUnchecked(e); 133 | throw new AssertionError("Unreachable"); 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/integration/ISysOutUser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.integration; 26 | 27 | interface ISysOutUser { 28 | void useSysOut(); 29 | } 30 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/integration/SysOutUser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.integration; 26 | 27 | class SysOutUser implements ISysOutUser { 28 | public void useSysOut() { 29 | System.out.println("Logged"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/integration/TestForClassloaderLeaks.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.integration; 26 | 27 | import java.lang.ref.ReferenceQueue; 28 | import java.lang.ref.WeakReference; 29 | 30 | import org.junit.Test; 31 | 32 | import uk.org.lidalia.sysoutslf4j.SysOutOverSLF4JTestCase; 33 | import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J; 34 | import uk.org.lidalia.testutils.SimpleClassloader; 35 | 36 | import static org.junit.Assert.assertNull; 37 | 38 | public class TestForClassloaderLeaks extends SysOutOverSLF4JTestCase { 39 | private static final int NUMBER_OF_CLASSLOADERS = 3; 40 | 41 | @Test 42 | public void classLoaderCanBeGarbageCollectedAfterCallingSendSystemOutAndErrToSLF4J() throws Exception { 43 | ClassLoaderHolder classLoaderHolder = new ClassLoaderHolder(0); 44 | 45 | givenThatSystemOutAndErrHaveBeenSentToSLF4JInAClassLoader(classLoaderHolder); 46 | whenNoReferencesToThatClassLoaderExist(classLoaderHolder); 47 | thenThatClassLoaderShouldBeGarbageCollected(classLoaderHolder); 48 | } 49 | 50 | private void givenThatSystemOutAndErrHaveBeenSentToSLF4JInAClassLoader(ClassLoaderHolder classLoaderHolder) throws Exception { 51 | callSendSystemOutAndErrToSLF4JInClassLoader(classLoaderHolder.classLoader); 52 | } 53 | 54 | private void whenNoReferencesToThatClassLoaderExist(ClassLoaderHolder classLoaderHolder) { 55 | destroyLocalReferenceToClassLoader(classLoaderHolder); 56 | } 57 | 58 | private void thenThatClassLoaderShouldBeGarbageCollected(ClassLoaderHolder classLoaderHolder) { 59 | assertThatClassLoaderHasBeenGarbageCollected(classLoaderHolder); 60 | } 61 | 62 | @Test 63 | public void multipleClassLoadersCanBeGarbageCollectedAfterCallingSendSystemOutAndErrToSLF4JWhenAllCreatedAndThenAllDestroyed() 64 | throws Exception { 65 | ClassLoaderHolder[] classLoaderHolders = new ClassLoaderHolder[NUMBER_OF_CLASSLOADERS]; 66 | for (int i = 0; i < NUMBER_OF_CLASSLOADERS; i++) { 67 | classLoaderHolders[i] = new ClassLoaderHolder(i); 68 | } 69 | givenThatSystemOutAndErrHaveBeenSentToSLF4JInSeveralClassLoaders(classLoaderHolders); 70 | whenNoReferencesToThoseClassLoadersExist(classLoaderHolders); 71 | thenThoseClassLoadersShouldBeGarbageCollected(classLoaderHolders); 72 | } 73 | 74 | private void givenThatSystemOutAndErrHaveBeenSentToSLF4JInSeveralClassLoaders( 75 | ClassLoaderHolder[] classLoaderHolders) throws Exception { 76 | for (ClassLoaderHolder classLoaderHolder : classLoaderHolders) { 77 | givenThatSystemOutAndErrHaveBeenSentToSLF4JInAClassLoader(classLoaderHolder); 78 | } 79 | } 80 | 81 | private void whenNoReferencesToThoseClassLoadersExist(ClassLoaderHolder[] classLoaderHolders) { 82 | for (ClassLoaderHolder classLoaderHolder : classLoaderHolders) { 83 | destroyLocalReferenceToClassLoader(classLoaderHolder); 84 | } 85 | } 86 | 87 | private void thenThoseClassLoadersShouldBeGarbageCollected(ClassLoaderHolder[] classLoaderHolders) { 88 | for (ClassLoaderHolder classLoaderHolder : classLoaderHolders) { 89 | assertThatClassLoaderHasBeenGarbageCollected(classLoaderHolder); 90 | } 91 | } 92 | 93 | private void destroyLocalReferenceToClassLoader(ClassLoaderHolder classLoaderHolder) { 94 | Thread.currentThread().setContextClassLoader(originalContextClassLoader); 95 | classLoaderHolder.classLoader = null; 96 | } 97 | 98 | private void assertThatClassLoaderHasBeenGarbageCollected(ClassLoaderHolder classLoaderHolder) { 99 | System.gc(); 100 | 101 | assertNull("classLoader " + classLoaderHolder.number + " has not been garbage collected", 102 | classLoaderHolder.referenceToClassLoader.get()); 103 | } 104 | 105 | private static class ClassLoaderHolder { 106 | private ClassLoader classLoader = SimpleClassloader.make(); 107 | private WeakReference referenceToClassLoader = 108 | new WeakReference(classLoader, new ReferenceQueue()); 109 | private int number; 110 | 111 | private ClassLoaderHolder(int number) { 112 | this.number = number; 113 | } 114 | } 115 | 116 | protected void callSendSystemOutAndErrToSLF4JInClassLoader(ClassLoader classLoader) throws Exception { 117 | Class sysOutOverSLF4JClass = classLoader.loadClass(SysOutOverSLF4J.class.getName()); 118 | Thread.currentThread().setContextClassLoader(classLoader); 119 | sysOutOverSLF4JClass.getMethod("sendSystemOutAndErrToSLF4J").invoke(sysOutOverSLF4JClass); 120 | Thread.currentThread().setContextClassLoader(originalContextClassLoader); 121 | } 122 | 123 | protected void callStopSendingSystemOutAndErrToSLF4JInClassLoader(ClassLoader classLoader) throws Exception { 124 | Class sysOutOverSLF4JClass = classLoader.loadClass(SysOutOverSLF4J.class.getName()); 125 | Thread.currentThread().setContextClassLoader(classLoader); 126 | sysOutOverSLF4JClass.getMethod("stopSendingSystemOutAndErrToSLF4J").invoke(sysOutOverSLF4JClass); 127 | Thread.currentThread().setContextClassLoader(originalContextClassLoader); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/integration/TestSysOutOverSLF4JInClassLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.integration; 26 | 27 | import java.io.ByteArrayOutputStream; 28 | import java.io.OutputStream; 29 | import java.io.PrintStream; 30 | import java.util.List; 31 | 32 | import org.junit.Test; 33 | import org.powermock.reflect.Whitebox; 34 | 35 | import uk.org.lidalia.slf4jtest.LoggingEvent; 36 | import uk.org.lidalia.slf4jtest.TestLogger; 37 | import uk.org.lidalia.slf4jtest.TestLoggerFactory; 38 | import uk.org.lidalia.sysoutslf4j.SysOutOverSLF4JTestCase; 39 | import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J; 40 | import uk.org.lidalia.sysoutslf4j.system.SystemOutput; 41 | import uk.org.lidalia.testutils.SimpleClassloader; 42 | 43 | import static org.hamcrest.CoreMatchers.containsString; 44 | import static org.hamcrest.MatcherAssert.assertThat; 45 | import static org.junit.Assert.assertEquals; 46 | 47 | public class TestSysOutOverSLF4JInClassLoader extends SysOutOverSLF4JTestCase { 48 | 49 | private final ClassLoader app1ClassLoader = SimpleClassloader.make(); 50 | 51 | @Test 52 | public void sysOutOverSLF4JWorksInsideAnotherClassLoader() throws Exception { 53 | callSendSystemOutAndErrToSLF4JInClassLoader(app1ClassLoader); 54 | 55 | ISysOutUser sysOutUser1 = newInstanceInClassLoader(ISysOutUser.class, app1ClassLoader, SysOutUser.class, new Class[]{}); 56 | 57 | Thread.currentThread().setContextClassLoader(app1ClassLoader); 58 | sysOutUser1.useSysOut(); 59 | 60 | List list1 = getLoggingEvents(app1ClassLoader); 61 | assertEquals(1, list1.size()); 62 | Class loggingEventClass = app1ClassLoader.loadClass(LoggingEvent.class.getName()); 63 | assertEquals("Logged", loggingEventClass.getDeclaredMethod("getMessage").invoke(list1.get(0))); 64 | } 65 | 66 | private E newInstanceInClassLoader( 67 | Class classToReturn, ClassLoader classLoader, Class classToGetInstanceOf, 68 | Class[] constructorArgTypes, Object... constructorArgs) throws Exception { 69 | Class class1 = classLoader.loadClass(classToGetInstanceOf.getName()); 70 | Object newInstance = Whitebox.invokeConstructor(class1, constructorArgTypes, constructorArgs); 71 | return CrossClassLoaderTestUtils.moveToCurrentClassLoader(classToReturn, newInstance); 72 | } 73 | 74 | static void clearTestLoggerFactory(ClassLoader classLoader) throws Exception { 75 | Class clazz = classLoader.loadClass(TestSysOutOverSLF4JInClassLoader.class.getName()); 76 | clazz.getDeclaredMethod("clearTestLoggerFactory").invoke(clazz); 77 | } 78 | 79 | public static void clearTestLoggerFactory() { 80 | TestLoggerFactory.clear(); 81 | } 82 | 83 | static List getLoggingEvents(ClassLoader classLoader) throws Exception { 84 | Class testLoggerFactoryClass = classLoader.loadClass(TestLoggerFactory.class.getName()); 85 | Object sysOutUserLogger = testLoggerFactoryClass.getDeclaredMethod("getTestLogger", String.class).invoke(testLoggerFactoryClass, SysOutUser.class.getName()); 86 | Class testLoggerClass = classLoader.loadClass(TestLogger.class.getName()); 87 | Object loggingEvents = testLoggerClass.getDeclaredMethod("getLoggingEvents").invoke(sysOutUserLogger); 88 | return CrossClassLoaderTestUtils.moveToCurrentClassLoader(List.class, loggingEvents); 89 | } 90 | 91 | @Test 92 | public void systemOutStillGoesToSystemOutInClassLoaderThatHasNotSentSysOutToLSF4J() throws Exception { 93 | OutputStream sysOutMock = setUpMockSystemOutput(SystemOutput.OUT); 94 | callSendSystemOutAndErrToSLF4JInClassLoader(app1ClassLoader); 95 | 96 | System.out.println("Hello again"); 97 | 98 | assertThat(sysOutMock.toString(), containsString("Hello again" + System.getProperty("line.separator"))); 99 | } 100 | 101 | private OutputStream setUpMockSystemOutput(SystemOutput systemOutput) { 102 | OutputStream sysOutMock = new ByteArrayOutputStream(); 103 | systemOutput.set(new PrintStream(sysOutMock)); 104 | return sysOutMock; 105 | } 106 | 107 | protected void callSendSystemOutAndErrToSLF4JInClassLoader(ClassLoader classLoader) throws Exception { 108 | Class sysOutOverSLF4JClass = classLoader.loadClass(SysOutOverSLF4J.class.getName()); 109 | Thread.currentThread().setContextClassLoader(classLoader); 110 | sysOutOverSLF4JClass.getMethod("sendSystemOutAndErrToSLF4J").invoke(sysOutOverSLF4JClass); 111 | Thread.currentThread().setContextClassLoader(originalContextClassLoader); 112 | } 113 | 114 | protected void callStopSendingSystemOutAndErrToSLF4JInClassLoader(ClassLoader classLoader) throws Exception { 115 | Class sysOutOverSLF4JClass = classLoader.loadClass(SysOutOverSLF4J.class.getName()); 116 | Thread.currentThread().setContextClassLoader(classLoader); 117 | sysOutOverSLF4JClass.getMethod("stopSendingSystemOutAndErrToSLF4J").invoke(sysOutOverSLF4JClass); 118 | Thread.currentThread().setContextClassLoader(originalContextClassLoader); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/sysoutslf4j/integration/TestSysOutOverSLF4JThreadSafety.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.integration; 26 | 27 | import java.util.ArrayList; 28 | import java.util.Collections; 29 | import java.util.List; 30 | import java.util.concurrent.CountDownLatch; 31 | import java.util.concurrent.ExecutorService; 32 | import java.util.concurrent.Executors; 33 | import java.util.concurrent.TimeUnit; 34 | 35 | import org.junit.Test; 36 | 37 | import uk.org.lidalia.lang.Task; 38 | import uk.org.lidalia.slf4jtest.LoggingEvent; 39 | import uk.org.lidalia.slf4jtest.TestLogger; 40 | import uk.org.lidalia.slf4jtest.TestLoggerFactory; 41 | import uk.org.lidalia.sysoutslf4j.SysOutOverSLF4JTestCase; 42 | import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J; 43 | 44 | import static org.junit.Assert.assertEquals; 45 | 46 | public class TestSysOutOverSLF4JThreadSafety extends SysOutOverSLF4JTestCase { 47 | 48 | private TestLogger log = TestLoggerFactory.getTestLogger(TestSysOutOverSLF4JThreadSafety.class); 49 | 50 | @Test 51 | public void sysoutOverSLF4JLogsCorrectlyInMultipleThreads() throws InterruptedException { 52 | 53 | SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); 54 | final CountDownLatch start = new CountDownLatch(1); 55 | 56 | ExecutorService executor = Executors.newFixedThreadPool(60); 57 | int numberOfTimesToPrint = 100; 58 | for (int i = 1; i <= numberOfTimesToPrint; i++) { 59 | final int count = i; 60 | executor.submit((Runnable) new Task() { 61 | @Override 62 | public void perform() throws Exception { 63 | start.await(); 64 | System.out.println("logging " + count); 65 | } 66 | }); 67 | } 68 | 69 | for (int i = 1; i <= numberOfTimesToPrint; i++) { 70 | final int count = i; 71 | executor.submit((Runnable) new Task() { 72 | @Override 73 | public void perform() throws Exception { 74 | start.await(); 75 | synchronized(System.out) { 76 | System.out.print("append1 "); 77 | System.out.print("append2 " + count); 78 | System.out.println(); 79 | } 80 | } 81 | }); 82 | } 83 | 84 | start.countDown(); 85 | executor.shutdown(); 86 | executor.awaitTermination(30, TimeUnit.SECONDS); 87 | List loggingEvents = log.getAllLoggingEvents(); 88 | assertEquals(numberOfTimesToPrint * 2, loggingEvents.size()); 89 | 90 | List messages = new ArrayList(); 91 | for (LoggingEvent loggingEvent : loggingEvents) { 92 | messages.add(loggingEvent.getMessage()); 93 | } 94 | Collections.sort(messages); 95 | 96 | List expectedMessages = new ArrayList(); 97 | for (int i = 1; i <= numberOfTimesToPrint; i++) { 98 | expectedMessages.add("append1 append2 " + i); 99 | } 100 | for (int i = numberOfTimesToPrint + 1; i <= (numberOfTimesToPrint * 2); i++) { 101 | expectedMessages.add("logging " + (i - numberOfTimesToPrint)); 102 | } 103 | Collections.sort(expectedMessages); 104 | assertEquals(expectedMessages, messages); 105 | 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/testutils/ClassCreationUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.testutils; 26 | 27 | import javassist.ClassPool; 28 | import javassist.CtClass; 29 | import javassist.LoaderClassPath; 30 | 31 | public final class ClassCreationUtils { 32 | 33 | public static Class makeClass(String className, Class... interfaces) throws Exception { 34 | 35 | final ClassPool pool = ClassPool.getDefault(); 36 | LoaderClassPath ccPath = new LoaderClassPath(Thread.currentThread().getContextClassLoader()); 37 | pool.insertClassPath(ccPath); 38 | 39 | CtClass cc; 40 | try { 41 | cc = pool.get(className); 42 | } catch (Exception e) { 43 | cc = pool.makeClass(className); 44 | CtClass[] interfaceCtClasses = new CtClass[interfaces.length]; 45 | for (int i = 0; i < interfaces.length; i++) { 46 | interfaceCtClasses[i] = pool.get(interfaces[i].getName()); 47 | } 48 | cc.setInterfaces(interfaceCtClasses); 49 | } 50 | Class newClass = cc.toClass(ClassCreationUtils.class.getClassLoader(), null); 51 | return newClass; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /sysout-over-slf4j-context/src/test/java/uk/org/lidalia/testutils/SimpleClassloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.testutils; 26 | 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.net.URL; 30 | import java.security.AccessController; 31 | import java.security.PrivilegedAction; 32 | 33 | import org.apache.commons.io.IOUtils; 34 | 35 | public class SimpleClassloader extends ClassLoader { 36 | private final ClassLoader realClassLoader = getClass().getClassLoader(); 37 | 38 | private SimpleClassloader(ClassLoader parent) { 39 | super(parent); 40 | } 41 | 42 | protected Class findClass(String name) { 43 | if (name.startsWith("uk.org.lidalia.sysoutslf4j.system")) { 44 | try { 45 | return realClassLoader.loadClass(name); 46 | } catch (ClassNotFoundException e) { 47 | throw new RuntimeException(e); 48 | } 49 | } 50 | String fileName = name.replace('.', '/') + ".class"; 51 | InputStream classAsStream = realClassLoader.getResourceAsStream(fileName); 52 | try { 53 | byte[] classAsByteArray = IOUtils.toByteArray(classAsStream); 54 | return defineClass(name, classAsByteArray, 0, classAsByteArray.length); 55 | } catch (IOException e) { 56 | throw new RuntimeException(e); 57 | } 58 | } 59 | 60 | @Override 61 | public URL getResource(String name) { 62 | return realClassLoader.getResource(name); 63 | } 64 | 65 | public static SimpleClassloader make() { 66 | return make(null); 67 | } 68 | 69 | public static SimpleClassloader make(final ClassLoader parent) { 70 | return AccessController.doPrivileged(new PrivilegedAction() { 71 | public SimpleClassloader run() { 72 | return new SimpleClassloader(parent); 73 | } 74 | }); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /sysout-over-slf4j-system/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | uk.org.lidalia.sysout-over-slf4j 6 | sysout-over-slf4j-parent 7 | 2.0.0-SNAPSHOT 8 | 9 | sysout-over-slf4j-system 10 | System Jar 11 | 12 | Contains all the classes that cannot be garbage collected as they are referenced from system classes, and so should be 13 | loaded by a classloader that is never discarded. 14 | 15 | 16 | 17 | 18 | uk.org.lidalia 19 | lidalia-test-dependencies 20 | pom 21 | 22 | 23 | uk.org.lidalia 24 | lidalia-lang 25 | test 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /sysout-over-slf4j-system/src/main/java/uk/org/lidalia/sysoutslf4j/system/PerContextPrintStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.system; 26 | 27 | import java.io.ByteArrayOutputStream; 28 | import java.io.IOException; 29 | import java.io.PrintStream; 30 | import java.util.Locale; 31 | 32 | public final class PerContextPrintStream extends PrintStream { // NOPMD superclass has too many methods 33 | 34 | private final PerContextStore printStreamStore; 35 | 36 | PerContextPrintStream(final PrintStream originalPrintStream) { 37 | // This ByteArrayOutputStream will be unused - we aren't going to touch 38 | // the super class. 39 | super(new ByteArrayOutputStream()); 40 | this.printStreamStore = new PerContextStore(originalPrintStream); 41 | } 42 | 43 | @Override 44 | public synchronized void println(final String string) { 45 | printStreamStore.get().println(string); 46 | } 47 | 48 | @Override 49 | public synchronized void println(final Object object) { 50 | printStreamStore.get().println(object); 51 | } 52 | 53 | @Override 54 | public synchronized void println() { 55 | printStreamStore.get().println(); 56 | } 57 | 58 | @Override 59 | public synchronized void println(final boolean bool) { 60 | printStreamStore.get().println(bool); 61 | } 62 | 63 | @Override 64 | public synchronized void println(final char character) { 65 | printStreamStore.get().println(character); 66 | } 67 | 68 | @Override 69 | public synchronized void println(final char[] charArray) { 70 | printStreamStore.get().println(charArray); 71 | } 72 | 73 | @Override 74 | public synchronized void println(final double doub) { 75 | printStreamStore.get().println(doub); 76 | } 77 | 78 | @Override 79 | public synchronized void println(final float floa) { 80 | printStreamStore.get().println(floa); 81 | } 82 | 83 | @Override 84 | public synchronized void println(final int integer) { 85 | printStreamStore.get().println(integer); 86 | } 87 | 88 | @Override 89 | public synchronized void println(final long lon) { 90 | printStreamStore.get().println(lon); 91 | } 92 | 93 | @Override 94 | public synchronized PrintStream append(final char character) { 95 | return printStreamStore.get().append(character); //QUERY should we return the delegate or the top level PrintStream? 96 | } 97 | 98 | @Override 99 | public synchronized PrintStream append(final CharSequence csq, final int start, final int end) { 100 | return printStreamStore.get().append(csq, start, end); 101 | } 102 | 103 | @Override 104 | public synchronized PrintStream append(final CharSequence csq) { 105 | return printStreamStore.get().append(csq); 106 | } 107 | 108 | @Override 109 | public boolean checkError() { 110 | return printStreamStore.get().checkError(); 111 | } 112 | 113 | @Override 114 | protected void setError() { 115 | throw new UnsupportedOperationException("Setting an error on a PerContextPrintStream does not make sense"); 116 | } 117 | 118 | @Override 119 | public synchronized void close() { 120 | printStreamStore.get().close(); 121 | } 122 | 123 | @Override 124 | public synchronized void flush() { 125 | printStreamStore.get().flush(); 126 | } 127 | 128 | @Override 129 | public synchronized PrintStream format(final Locale locale, final String format, final Object... args) { 130 | return printStreamStore.get().format(locale, format, args); 131 | } 132 | 133 | @Override 134 | public synchronized PrintStream format(final String format, final Object... args) { 135 | return printStreamStore.get().format(format, args); 136 | } 137 | 138 | @Override 139 | public synchronized void print(final boolean bool) { 140 | printStreamStore.get().print(bool); 141 | } 142 | 143 | @Override 144 | public synchronized void print(final char character) { 145 | printStreamStore.get().print(character); 146 | } 147 | 148 | @Override 149 | public synchronized void print(final char[] charArray) { 150 | printStreamStore.get().print(charArray); 151 | } 152 | 153 | @Override 154 | public synchronized void print(final double doubl) { 155 | printStreamStore.get().print(doubl); 156 | } 157 | 158 | @Override 159 | public synchronized void print(final float floa) { 160 | printStreamStore.get().print(floa); 161 | } 162 | 163 | @Override 164 | public synchronized void print(final int integer) { 165 | printStreamStore.get().print(integer); 166 | } 167 | 168 | @Override 169 | public synchronized void print(final long lon) { 170 | printStreamStore.get().print(lon); 171 | } 172 | 173 | @Override 174 | public synchronized void print(final Object object) { 175 | printStreamStore.get().print(object); 176 | } 177 | 178 | @Override 179 | public synchronized void print(final String string) { 180 | printStreamStore.get().print(string); 181 | } 182 | 183 | @Override 184 | public synchronized PrintStream printf(final Locale locale, final String format, final Object... args) { 185 | return printStreamStore.get().printf(locale, format, args); 186 | } 187 | 188 | @Override 189 | public synchronized PrintStream printf(final String format, final Object... args) { 190 | return printStreamStore.get().printf(format, args); 191 | } 192 | 193 | @Override 194 | public synchronized void write(final byte[] buf, final int off, final int len) { 195 | printStreamStore.get().write(buf, off, len); 196 | } 197 | 198 | @Override 199 | public synchronized void write(final int integer) { 200 | printStreamStore.get().write(integer); 201 | } 202 | 203 | @Override 204 | public synchronized void write(final byte[] bytes) throws IOException { 205 | printStreamStore.get().write(bytes); 206 | } 207 | 208 | void registerPrintStreamForThisContext(final PrintStream printStreamForThisContext) { 209 | printStreamStore.put(printStreamForThisContext); 210 | } 211 | 212 | void deregisterPrintStreamForThisContext() { 213 | printStreamStore.remove(); 214 | } 215 | 216 | PrintStream getOriginalPrintStream() { 217 | return printStreamStore.getDefaultValue(); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /sysout-over-slf4j-system/src/main/java/uk/org/lidalia/sysoutslf4j/system/PerContextStore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.system; 26 | 27 | import java.lang.ref.WeakReference; 28 | import java.util.Map; 29 | import java.util.WeakHashMap; 30 | import java.util.concurrent.locks.Lock; 31 | import java.util.concurrent.locks.ReadWriteLock; 32 | import java.util.concurrent.locks.ReentrantReadWriteLock; 33 | 34 | 35 | class PerContextStore { 36 | 37 | private final Map> loggerAppenderMap = 38 | new WeakHashMap>(); 39 | private final T defaultValue; 40 | 41 | private final ReadWriteLock lock = new ReentrantReadWriteLock(); 42 | private final Lock readLock = lock.readLock(); 43 | private final Lock writeLock = lock.writeLock(); 44 | 45 | PerContextStore() { 46 | this(null); 47 | } 48 | 49 | PerContextStore(final T defaultValue) { 50 | this.defaultValue = defaultValue; 51 | } 52 | 53 | T get() { 54 | readLock.lock(); 55 | try { 56 | return get(contextClassLoader()); 57 | } finally { 58 | readLock.unlock(); 59 | } 60 | } 61 | 62 | T getDefaultValue() { 63 | return defaultValue; 64 | } 65 | 66 | // TODO write test for when weakreference returns null... 67 | private T get(final ClassLoader classLoader) { 68 | final WeakReference loggerAppenderReference = loggerAppenderMap.get(classLoader); 69 | final T result; 70 | if (loggerAppenderReference == null) { 71 | if (classLoader == null) { 72 | result = defaultValue; 73 | } else { 74 | result = get(classLoader.getParent()); 75 | } 76 | } else { 77 | result = loggerAppenderReference.get(); 78 | } 79 | return result; 80 | } 81 | 82 | void put(final T loggerAppender) { 83 | writeLock.lock(); 84 | try { 85 | loggerAppenderMap.put(contextClassLoader(), new WeakReference(loggerAppender)); 86 | } finally { 87 | writeLock.unlock(); 88 | } 89 | } 90 | 91 | void remove() { 92 | writeLock.lock(); 93 | try { 94 | loggerAppenderMap.remove(contextClassLoader()); 95 | } finally { 96 | writeLock.unlock(); 97 | } 98 | } 99 | 100 | private ClassLoader contextClassLoader() { 101 | return Thread.currentThread().getContextClassLoader(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /sysout-over-slf4j-system/src/main/java/uk/org/lidalia/sysoutslf4j/system/PerContextSystemOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.system; 26 | 27 | import java.io.PrintStream; 28 | import java.util.concurrent.locks.Lock; 29 | 30 | public enum PerContextSystemOutput { 31 | 32 | OUT(SystemOutput.OUT), ERR(SystemOutput.ERR); 33 | 34 | private final SystemOutput systemOutput; 35 | 36 | private PerContextSystemOutput(final SystemOutput systemOutput) { 37 | this.systemOutput = systemOutput; 38 | } 39 | 40 | public boolean isPerContextPrintStream() { 41 | return systemOutput.get() instanceof PerContextPrintStream; 42 | } 43 | 44 | public void restoreOriginalPrintStream() { 45 | final Lock writeLock = systemOutput.getLock().writeLock(); 46 | writeLock.lock(); 47 | try { 48 | if (isPerContextPrintStream()) { 49 | systemOutput.set(getPerContextPrintStream().getOriginalPrintStream()); 50 | } 51 | } finally { 52 | writeLock.unlock(); 53 | } 54 | } 55 | 56 | public PrintStream getOriginalPrintStream() { 57 | final PrintStream result; 58 | final Lock readLock = systemOutput.getLock().readLock(); 59 | readLock.lock(); 60 | try { 61 | if (isPerContextPrintStream()) { 62 | result = getPerContextPrintStream().getOriginalPrintStream(); 63 | } else { 64 | result = systemOutput.get(); 65 | } 66 | return result; 67 | } finally { 68 | readLock.unlock(); 69 | } 70 | } 71 | 72 | private PerContextPrintStream getPerContextPrintStream() { 73 | return (PerContextPrintStream) systemOutput.get(); 74 | } 75 | 76 | public void deregisterPrintStreamForThisContext() { 77 | final Lock readLock = systemOutput.getLock().readLock(); 78 | readLock.lock(); 79 | try { 80 | if (isPerContextPrintStream()) { 81 | getPerContextPrintStream().deregisterPrintStreamForThisContext(); 82 | } 83 | } finally { 84 | readLock.unlock(); 85 | } 86 | } 87 | 88 | public void registerPrintStreamForThisContext(final PrintStream printStreamForThisContext) { 89 | final Lock writeLock = systemOutput.getLock().writeLock(); 90 | writeLock.lock(); 91 | try { 92 | makePerContextPrintStream(); 93 | getPerContextPrintStream().registerPrintStreamForThisContext(printStreamForThisContext); 94 | } finally { 95 | writeLock.unlock(); 96 | } 97 | } 98 | 99 | private void makePerContextPrintStream() { 100 | if (!isPerContextPrintStream()) { 101 | systemOutput.set(buildPerContextPrintStream()); 102 | } 103 | } 104 | 105 | private PerContextPrintStream buildPerContextPrintStream() { 106 | final PrintStream originalPrintStream = systemOutput.get(); 107 | return new PerContextPrintStream(originalPrintStream); 108 | } 109 | 110 | public static PerContextSystemOutput findByName(String name) { 111 | for (PerContextSystemOutput systemOutput : PerContextSystemOutput.values()) { 112 | if (systemOutput.systemOutput.getName().equalsIgnoreCase(name)) { 113 | return systemOutput; 114 | } 115 | } 116 | throw new IllegalArgumentException("No system output [" + name + "]; valid values are " + names()); 117 | } 118 | 119 | private static String names() { 120 | StringBuilder builder = new StringBuilder("["); 121 | PerContextSystemOutput[] values = values(); 122 | for (int i = 0; i < values.length; i++) { 123 | builder.append(values[i].systemOutput.getName()); 124 | if (i < values.length - 1) { 125 | builder.append(","); 126 | } 127 | } 128 | builder.append("]"); 129 | return builder.toString(); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /sysout-over-slf4j-system/src/main/java/uk/org/lidalia/sysoutslf4j/system/SystemOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.system; 26 | 27 | import java.io.PrintStream; 28 | import java.util.concurrent.locks.Lock; 29 | import java.util.concurrent.locks.ReadWriteLock; 30 | import java.util.concurrent.locks.ReentrantReadWriteLock; 31 | 32 | public enum SystemOutput { 33 | 34 | OUT("System.out") { 35 | public PrintStream get() { 36 | final Lock readLock = getLock().readLock(); 37 | readLock.lock(); 38 | try { 39 | return System.out; 40 | } finally { 41 | readLock.unlock(); 42 | } 43 | } 44 | 45 | public void set(final PrintStream newPrintStream) { 46 | final Lock writeLock = getLock().writeLock(); 47 | writeLock.lock(); 48 | try { 49 | System.setOut(newPrintStream); 50 | } finally { 51 | writeLock.unlock(); 52 | } 53 | } 54 | }, ERR("System.err") { 55 | public PrintStream get() { 56 | final Lock readLock = getLock().readLock(); 57 | readLock.lock(); 58 | try { 59 | return System.err; 60 | } finally { 61 | readLock.unlock(); 62 | } 63 | } 64 | 65 | public void set(final PrintStream newPrintStream) { 66 | final Lock writeLock = getLock().writeLock(); 67 | writeLock.lock(); 68 | try { 69 | System.setErr(newPrintStream); 70 | } finally { 71 | writeLock.unlock(); 72 | } 73 | } 74 | }; 75 | 76 | public abstract PrintStream get(); 77 | public abstract void set(PrintStream newPrintStream); 78 | 79 | private final String name; 80 | private final ReadWriteLock lock = new ReentrantReadWriteLock(); 81 | 82 | private SystemOutput(final String name) { 83 | this.name = name; 84 | } 85 | 86 | public ReadWriteLock getLock() { 87 | return lock; 88 | } 89 | 90 | @Override 91 | public String toString() { 92 | return name; 93 | } 94 | 95 | public String getName() { 96 | return name; 97 | } 98 | 99 | public static SystemOutput findByName(String name) { 100 | for (SystemOutput systemOutput : SystemOutput.values()) { 101 | if (systemOutput.name.equalsIgnoreCase(name)) { 102 | return systemOutput; 103 | } 104 | } 105 | throw new IllegalArgumentException("No system output [" + name + "]; valid values are " + names()); 106 | } 107 | 108 | private static String names() { 109 | StringBuilder builder = new StringBuilder("["); 110 | SystemOutput[] values = values(); 111 | for (int i = 0; i < values.length; i++) { 112 | builder.append(values[i].getName()); 113 | if (i < values.length - 1) { 114 | builder.append(","); 115 | } 116 | } 117 | builder.append("]"); 118 | return builder.toString(); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /sysout-over-slf4j-system/src/test/java/uk/org/lidalia/sysoutslf4j/system/PerContextPrintStreamTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.system; 26 | 27 | import java.io.ByteArrayOutputStream; 28 | import java.io.PrintStream; 29 | import java.lang.reflect.Array; 30 | import java.lang.reflect.Method; 31 | import java.util.ArrayList; 32 | import java.util.Arrays; 33 | import java.util.List; 34 | 35 | import org.junit.Test; 36 | import org.junit.runner.RunWith; 37 | import org.powermock.core.classloader.annotations.PrepareForTest; 38 | import org.powermock.modules.junit4.PowerMockRunner; 39 | 40 | import uk.org.lidalia.lang.Classes; 41 | 42 | import static org.junit.Assert.assertEquals; 43 | import static org.junit.Assert.assertSame; 44 | import static org.mockito.Mockito.mock; 45 | import static org.mockito.Mockito.verify; 46 | import static org.mockito.Mockito.when; 47 | import static org.powermock.api.mockito.PowerMockito.whenNew; 48 | import static uk.org.lidalia.test.ShouldThrow.shouldThrow; 49 | 50 | @RunWith(PowerMockRunner.class) 51 | @PrepareForTest(PerContextPrintStream.class) 52 | public class PerContextPrintStreamTests { 53 | 54 | private PrintStream originalPrintStreamMock; 55 | private PerContextStore perContextStoreMock; 56 | private PrintStream contextPrintStreamMock; 57 | private PerContextPrintStream perContextPrintStream; 58 | 59 | @SuppressWarnings("unchecked") 60 | public void setUpMocks() throws Exception { 61 | originalPrintStreamMock = mock(PrintStream.class); 62 | perContextStoreMock = mock(PerContextStore.class); 63 | contextPrintStreamMock = mock(PrintStream.class); 64 | when(perContextStoreMock.get()).thenReturn(contextPrintStreamMock); 65 | whenNew(PerContextStore.class).withArguments(originalPrintStreamMock).thenReturn(perContextStoreMock); 66 | perContextPrintStream = new PerContextPrintStream(originalPrintStreamMock); 67 | } 68 | 69 | @Test 70 | public void allPublicPrintStreamMethodsOnPerContextPrintStreamDelegateToTheSameMethodOnAPrintStreamRetrievedFromTheStore() throws Exception { 71 | List printStreamMethods = new ArrayList(Arrays.asList(PrintStream.class.getMethods())); 72 | printStreamMethods.removeAll(Arrays.asList(Object.class.getMethods())); 73 | 74 | for (Method method : printStreamMethods) { 75 | setUpMocks(); 76 | Object[] args = getParameterValuesFor(method); 77 | if (method.getReturnType() == void.class) { 78 | assertMethodDelegatesToContextPrintStream(method, args); 79 | } else { 80 | assertMethodDelegatesToContextPrintStreamAndReturnsResult(method, args); 81 | } 82 | } 83 | } 84 | 85 | private void assertMethodDelegatesToContextPrintStreamAndReturnsResult(Method method, Object[] args) throws Exception { 86 | Object result = getValueFor(method.getReturnType()); 87 | when(method.invoke(contextPrintStreamMock, args)).thenReturn(result); 88 | 89 | Object actualResult = method.invoke(perContextPrintStream, args); 90 | 91 | assertEquals(method + " on " + PerContextPrintStream.class + " return value: ", 92 | result, actualResult); 93 | } 94 | 95 | private void assertMethodDelegatesToContextPrintStream(Method method, Object[] args) throws Exception { 96 | method.invoke(perContextPrintStream, args); 97 | method.invoke(verify(contextPrintStreamMock), args); 98 | } 99 | 100 | @Test 101 | public void setErrorThrowsUnsupportedOperationException() throws Exception { 102 | setUpMocks(); 103 | UnsupportedOperationException exception = shouldThrow(UnsupportedOperationException.class, new Runnable() { 104 | @Override 105 | public void run() { 106 | perContextPrintStream.setError(); 107 | } 108 | }); 109 | assertEquals("Setting an error on a PerContextPrintStream does not make sense", exception.getMessage()); 110 | } 111 | 112 | @Test 113 | public void registerPrintStreamForThisContextDelgatesToStore() throws Exception { 114 | setUpMocks(); 115 | perContextPrintStream.registerPrintStreamForThisContext(contextPrintStreamMock); 116 | verify(perContextStoreMock).put(contextPrintStreamMock); 117 | } 118 | 119 | @Test 120 | public void deregisterPrintStreamForThisContextDelegatesToStore() throws Exception { 121 | setUpMocks(); 122 | perContextPrintStream.deregisterPrintStreamForThisContext(); 123 | verify(perContextStoreMock).remove(); 124 | } 125 | 126 | @Test 127 | public void getOriginalPrintStreamReturnsOriginalPrintStream() { 128 | perContextPrintStream = new PerContextPrintStream(System.err); 129 | assertSame(System.err, perContextPrintStream.getOriginalPrintStream()); 130 | } 131 | 132 | private static Object[] getParameterValuesFor(Method method) throws Exception { 133 | Class[] parameterTypes = method.getParameterTypes(); 134 | List results = new ArrayList(); 135 | for (Class type : parameterTypes) { 136 | results.add(getValueFor(type)); 137 | } 138 | return results.toArray(); 139 | } 140 | 141 | private static Object getValueFor(Class type) 142 | throws InstantiationException, IllegalAccessException { 143 | Object value; 144 | if (type == char.class) { 145 | value = 'a'; 146 | } else if (type == boolean.class) { 147 | value = true; 148 | } else if (type == byte.class) { 149 | value = (byte) 5; 150 | } else if (type == short.class) { 151 | value = (short) 10; 152 | } else if (type == int.class) { 153 | value = 20; 154 | } else if (type == long.class) { 155 | value = 30L; 156 | } else if (type == float.class) { 157 | value = 12.0f; 158 | } else if (type == double.class) { 159 | value = 24.0f; 160 | } else if (type.isArray()) { 161 | value = Array.newInstance(type.getComponentType(), 2); 162 | Array.set(value, 0, getValueFor(type.getComponentType())); 163 | } else if (Classes.hasConstructor(type)) { 164 | value = type.newInstance(); 165 | } else if (type == CharSequence.class) { 166 | value = "charseq"; 167 | } else if (type == PrintStream.class) { 168 | value = new PrintStream(new ByteArrayOutputStream()); 169 | } else { 170 | value = null; 171 | } 172 | return value; 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /sysout-over-slf4j-system/src/test/java/uk/org/lidalia/sysoutslf4j/system/PerContextStoreMemoryManagementTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.system; 26 | 27 | import java.lang.ref.ReferenceQueue; 28 | import java.lang.ref.WeakReference; 29 | 30 | import org.junit.Test; 31 | 32 | import static org.junit.Assert.assertNull; 33 | 34 | public class PerContextStoreMemoryManagementTests extends SysOutOverSLF4JTestCase { 35 | 36 | private final PerContextStore storeUnderTest = new PerContextStore(); 37 | 38 | private ClassLoader classLoader = new ClassLoader(){}; 39 | private final WeakReference refToClassLoader = 40 | new WeakReference(classLoader, new ReferenceQueue()); 41 | private String valueToStore = "some value"; 42 | 43 | @Test 44 | public void loggerAppenderStoreDoesNotCauseAClassLoaderLeak() throws Exception { 45 | storeLoggerAppenderAgainstClassLoader(); 46 | removeLocalReferenceToClassLoader(); 47 | removeLocalReferenceToLoggerAppenderAndGarbageCollect(); 48 | assertClassLoaderHasBeenGarbageCollected(); 49 | } 50 | 51 | private void storeLoggerAppenderAgainstClassLoader() { 52 | Thread.currentThread().setContextClassLoader(classLoader); 53 | storeUnderTest.put(valueToStore); 54 | } 55 | 56 | private void removeLocalReferenceToClassLoader() { 57 | Thread.currentThread().setContextClassLoader(originalContextClassLoader); 58 | classLoader = null; 59 | } 60 | 61 | private void removeLocalReferenceToLoggerAppenderAndGarbageCollect() { 62 | valueToStore = null; 63 | System.gc(); 64 | } 65 | 66 | 67 | private void assertClassLoaderHasBeenGarbageCollected() { 68 | assertNull("classloader has not been garbage collected", refToClassLoader.get()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /sysout-over-slf4j-system/src/test/java/uk/org/lidalia/sysoutslf4j/system/PerContextStoreTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.system; 26 | 27 | import org.junit.Test; 28 | 29 | import static java.lang.Thread.currentThread; 30 | import static org.junit.Assert.assertEquals; 31 | import static org.junit.Assert.assertNull; 32 | import static org.junit.Assert.assertSame; 33 | 34 | public class PerContextStoreTests extends SysOutOverSLF4JTestCase { 35 | 36 | private final PerContextStore storeUnderTest = new PerContextStore(); 37 | private final ClassLoader[] classLoaders = { new ClassLoader() { }, new ClassLoader() { } }; 38 | private final String[] objectsToStore = { "1", "2" }; 39 | 40 | @Test 41 | public void perContextStoreStoresValueRelativeToContextClassLoader() { 42 | storeValuesAgainstDifferentContextClassLoaders(); 43 | assertCorrectValueReturnedForEachClassLoader(); 44 | } 45 | 46 | private void storeValuesAgainstDifferentContextClassLoaders() { 47 | for (int i = 0; i < classLoaders.length; i++) { 48 | currentThread().setContextClassLoader(classLoaders[i]); 49 | storeUnderTest.put(objectsToStore[i]); 50 | } 51 | } 52 | 53 | private void assertCorrectValueReturnedForEachClassLoader() { 54 | for (int i = 0; i < classLoaders.length; i++) { 55 | currentThread().setContextClassLoader(classLoaders[i]); 56 | assertSame(objectsToStore[i], storeUnderTest.get()); 57 | } 58 | } 59 | 60 | @Test 61 | public void perContextStoreWorksIfContextClassLoaderIsNull() { 62 | currentThread().setContextClassLoader(null); 63 | storeUnderTest.put("value"); 64 | assertNull(currentThread().getContextClassLoader()); 65 | assertEquals("value", storeUnderTest.get()); 66 | } 67 | 68 | @Test 69 | public void perContextStoreReturnsValueStoredAgainstParentOfContextClassLoader() { 70 | ClassLoader parent = new ClassLoader() { }; 71 | String value = "aValue"; 72 | currentThread().setContextClassLoader(parent); 73 | storeUnderTest.put(value); 74 | 75 | ClassLoader child = new ClassLoader(parent) { }; 76 | currentThread().setContextClassLoader(child); 77 | 78 | assertSame(value, storeUnderTest.get()); 79 | } 80 | 81 | @Test 82 | public void perContextStoreReturnsNullIfNoValueStoredAndNoDefaultSet() { 83 | assertNull(storeUnderTest.get()); 84 | } 85 | 86 | @Test 87 | public void perContextStoreReturnsDefaultIfNoClassLoaderStored() { 88 | PerContextStore storeUnderTest = new PerContextStore("default"); 89 | assertEquals("default", storeUnderTest.get()); 90 | } 91 | 92 | @Test 93 | public void removeRemovesValueForCurrentContextClassLoader() { 94 | storeValuesAgainstDifferentContextClassLoaders(); 95 | currentThread().setContextClassLoader(classLoaders[0]); 96 | storeUnderTest.remove(); 97 | assertNull(storeUnderTest.get()); 98 | for (int i = 1; i < classLoaders.length; i++) { 99 | currentThread().setContextClassLoader(classLoaders[i]); 100 | assertSame(objectsToStore[i], storeUnderTest.get()); 101 | } 102 | } 103 | 104 | @Test 105 | public void getDefaultValueReturnsDefaultValue() { 106 | PerContextStore storeUnderTest = new PerContextStore("default"); 107 | assertEquals("default", storeUnderTest.getDefaultValue()); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /sysout-over-slf4j-system/src/test/java/uk/org/lidalia/sysoutslf4j/system/PerContextSystemOutputTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.system; 26 | 27 | import java.io.ByteArrayOutputStream; 28 | import java.io.PrintStream; 29 | 30 | import org.junit.Test; 31 | import org.junit.runner.RunWith; 32 | import org.powermock.core.classloader.annotations.PrepareForTest; 33 | import org.powermock.modules.junit4.PowerMockRunner; 34 | 35 | import static org.junit.Assert.assertFalse; 36 | import static org.junit.Assert.assertSame; 37 | import static org.junit.Assert.assertTrue; 38 | import static org.mockito.Mockito.mock; 39 | import static org.mockito.Mockito.verify; 40 | import static org.powermock.api.mockito.PowerMockito.whenNew; 41 | 42 | 43 | @RunWith(PowerMockRunner.class) 44 | @PrepareForTest({PerContextPrintStream.class, PerContextSystemOutput.class}) 45 | public class PerContextSystemOutputTests extends SysOutOverSLF4JTestCase { 46 | 47 | @Test 48 | public void isPerContextPrintStreamReturnsFalseWhenSystemOutIsPerContextPrintStream() { 49 | assertFalse(PerContextSystemOutput.OUT.isPerContextPrintStream()); 50 | assertFalse(PerContextSystemOutput.ERR.isPerContextPrintStream()); 51 | } 52 | 53 | @Test 54 | public void isPerContextPrintStreamReturnsTrueWhenSystemOutIsPerContextPrintStream() { 55 | System.setOut(new PerContextPrintStream(System.out)); 56 | assertTrue(PerContextSystemOutput.OUT.isPerContextPrintStream()); 57 | 58 | System.setErr(new PerContextPrintStream(System.err)); 59 | assertTrue(PerContextSystemOutput.ERR.isPerContextPrintStream()); 60 | } 61 | 62 | @Test 63 | public void restoreOriginalPrintStreamDoesNothingIfOutputIsOriginalPrintStream() { 64 | assertRestoreOriginalPrintStreamDoesNothingIfOutputIsOriginalPrintStream(SystemOutput.OUT, PerContextSystemOutput.OUT); 65 | assertRestoreOriginalPrintStreamDoesNothingIfOutputIsOriginalPrintStream(SystemOutput.ERR, PerContextSystemOutput.ERR); 66 | } 67 | 68 | private void assertRestoreOriginalPrintStreamDoesNothingIfOutputIsOriginalPrintStream(SystemOutput output, PerContextSystemOutput perContextOutput) { 69 | PrintStream original = output.get(); 70 | perContextOutput.restoreOriginalPrintStream(); 71 | assertSame(original, output.get()); 72 | } 73 | 74 | @Test 75 | public void restoreOriginalPrintStreamDoesNothingIfOutputIsNotPerContextPrintStream() { 76 | assertRestoreOriginalPrintStreamDoesNothingIfOutputIsNotPerContextPrintStream(SystemOutput.OUT, PerContextSystemOutput.OUT); 77 | assertRestoreOriginalPrintStreamDoesNothingIfOutputIsNotPerContextPrintStream(SystemOutput.ERR, PerContextSystemOutput.ERR); 78 | } 79 | 80 | private void assertRestoreOriginalPrintStreamDoesNothingIfOutputIsNotPerContextPrintStream(SystemOutput output, PerContextSystemOutput perContextOutput) { 81 | PrintStream other = new PrintStream(new ByteArrayOutputStream()); 82 | output.set(other); 83 | perContextOutput.restoreOriginalPrintStream(); 84 | assertSame(other, output.get()); 85 | } 86 | 87 | @Test 88 | public void restoreOriginalPrintStreamRestoresOriginalPrintStreamIfOutputIsPerContextPrintStream() { 89 | assertRestoreOriginalPrintStreamRestoresOriginalPrintStreamIfOutputIsPerContextPrintStream(SystemOutput.OUT, PerContextSystemOutput.OUT); 90 | assertRestoreOriginalPrintStreamRestoresOriginalPrintStreamIfOutputIsPerContextPrintStream(SystemOutput.ERR, PerContextSystemOutput.ERR); 91 | } 92 | 93 | private void assertRestoreOriginalPrintStreamRestoresOriginalPrintStreamIfOutputIsPerContextPrintStream(SystemOutput output, PerContextSystemOutput perContextOutput) { 94 | PrintStream original = output.get(); 95 | output.set(new PerContextPrintStream(output.get())); 96 | perContextOutput.restoreOriginalPrintStream(); 97 | assertSame(original, output.get()); 98 | } 99 | 100 | @Test 101 | public void getOriginalPrintStreamReturnsOriginalWhenOutputIsOriginalPrintStream() { 102 | assertSame(SystemOutput.OUT.get(), PerContextSystemOutput.OUT.getOriginalPrintStream()); 103 | assertSame(SystemOutput.ERR.get(), PerContextSystemOutput.ERR.getOriginalPrintStream()); 104 | } 105 | 106 | @Test 107 | public void getOriginalPrintStreamReturnsCurrentWhenOutputIsNotPerContextPrintStream() { 108 | getOriginalPrintStreamReturnsCurrentWhenOutputIsNotPerContextPrintStream(SystemOutput.OUT, PerContextSystemOutput.OUT); 109 | getOriginalPrintStreamReturnsCurrentWhenOutputIsNotPerContextPrintStream(SystemOutput.ERR, PerContextSystemOutput.ERR); 110 | } 111 | 112 | private void getOriginalPrintStreamReturnsCurrentWhenOutputIsNotPerContextPrintStream(SystemOutput output, PerContextSystemOutput perContextOutput) { 113 | PrintStream other = new PrintStream(new ByteArrayOutputStream()); 114 | output.set(other); 115 | assertSame(other, perContextOutput.getOriginalPrintStream()); 116 | } 117 | 118 | @Test 119 | public void getOriginalPrintStreamReturnsOriginalWhenOutputIsPerContextPrintStream() { 120 | getOriginalPrintStreamReturnsOriginalWhenOutputIsPerContextPrintStream(SystemOutput.OUT, PerContextSystemOutput.OUT); 121 | getOriginalPrintStreamReturnsOriginalWhenOutputIsPerContextPrintStream(SystemOutput.ERR, PerContextSystemOutput.ERR); 122 | } 123 | 124 | private void getOriginalPrintStreamReturnsOriginalWhenOutputIsPerContextPrintStream(SystemOutput output, PerContextSystemOutput perContextOutput) { 125 | PrintStream original = output.get(); 126 | output.set(new PerContextPrintStream(output.get())); 127 | assertSame(original, perContextOutput.getOriginalPrintStream()); 128 | } 129 | 130 | @Test 131 | public void registerLoggerAppenderMakesPerContextPrintStreamAndRegistersLoggerAppenderIfSysOutIsNotPerContextPrintStream() throws Exception { 132 | registerLoggerAppenderMakesPerContextPrintStreamAndRegistersLoggerAppenderIfOutputIsNotPerContextPrintStream( 133 | SystemOutput.OUT, PerContextSystemOutput.OUT); 134 | } 135 | 136 | @Test 137 | public void registerLoggerAppenderMakesPerContextPrintStreamAndRegistersLoggerAppenderIfSysErrIsNotPerContextPrintStream() throws Exception { 138 | registerLoggerAppenderMakesPerContextPrintStreamAndRegistersLoggerAppenderIfOutputIsNotPerContextPrintStream( 139 | SystemOutput.ERR, PerContextSystemOutput.ERR); 140 | } 141 | 142 | private void registerLoggerAppenderMakesPerContextPrintStreamAndRegistersLoggerAppenderIfOutputIsNotPerContextPrintStream( 143 | final SystemOutput output, final PerContextSystemOutput perContextOutput) throws Exception { 144 | PrintStream original = output.get(); 145 | PrintStream toRegister = new PrintStream(new ByteArrayOutputStream()); 146 | PerContextPrintStream perContextPrintStreamMock = mock(PerContextPrintStream.class); 147 | 148 | whenNew(PerContextPrintStream.class).withArguments(original).thenReturn(perContextPrintStreamMock); 149 | 150 | perContextOutput.registerPrintStreamForThisContext(toRegister); 151 | 152 | assertSame(perContextPrintStreamMock, output.get()); 153 | verify(perContextPrintStreamMock).registerPrintStreamForThisContext(toRegister); 154 | } 155 | 156 | @Test 157 | public void registerLoggerAppenderRegistersLoggerAppenderIfSystemOutIsPerContextPrintStream() { 158 | registerLoggerAppenderRegistersLoggerAppenderIfOutputIsPerContextPrintStream(SystemOutput.OUT, PerContextSystemOutput.OUT); 159 | } 160 | 161 | @Test 162 | public void registerLoggerAppenderRegistersLoggerAppenderIfSystemErrIsPerContextPrintStream() { 163 | registerLoggerAppenderRegistersLoggerAppenderIfOutputIsPerContextPrintStream(SystemOutput.ERR, PerContextSystemOutput.ERR); 164 | } 165 | 166 | private void registerLoggerAppenderRegistersLoggerAppenderIfOutputIsPerContextPrintStream(SystemOutput output, PerContextSystemOutput perContextOutput) { 167 | PerContextPrintStream perContextPrintStreamMock = mock(PerContextPrintStream.class); 168 | PrintStream toRegister = new PrintStream(new ByteArrayOutputStream()); 169 | 170 | output.set(perContextPrintStreamMock); 171 | perContextOutput.registerPrintStreamForThisContext(toRegister); 172 | 173 | verify(perContextPrintStreamMock).registerPrintStreamForThisContext(toRegister); 174 | } 175 | 176 | @Test 177 | public void deregisterLoggerAppenderDoesNothingIfOutputIsNotPerContextPrintStream() { 178 | PerContextSystemOutput.OUT.deregisterPrintStreamForThisContext(); 179 | PerContextSystemOutput.ERR.deregisterPrintStreamForThisContext(); 180 | // Nothing happens 181 | } 182 | 183 | @Test 184 | public void deregisterLoggerAppenderDeregistersAppenderIfSystemOutIsPerContextPrintStream() { 185 | deregisterLoggerAppenderDeregistersAppenderIfOutputIsPerContextPrintStream(SystemOutput.OUT, PerContextSystemOutput.OUT); 186 | } 187 | 188 | @Test 189 | public void deregisterLoggerAppenderDeregistersAppenderIfSystemErrIsPerContextPrintStream() { 190 | deregisterLoggerAppenderDeregistersAppenderIfOutputIsPerContextPrintStream(SystemOutput.ERR, PerContextSystemOutput.ERR); 191 | } 192 | 193 | private void deregisterLoggerAppenderDeregistersAppenderIfOutputIsPerContextPrintStream(SystemOutput output, PerContextSystemOutput perContextOutput) { 194 | PerContextPrintStream perContextPrintStreamMock = mock(PerContextPrintStream.class); 195 | 196 | output.set(perContextPrintStreamMock); 197 | perContextOutput.deregisterPrintStreamForThisContext(); 198 | 199 | verify(perContextPrintStreamMock).deregisterPrintStreamForThisContext(); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /sysout-over-slf4j-system/src/test/java/uk/org/lidalia/sysoutslf4j/system/SysOutOverSLF4JTestCase.java: -------------------------------------------------------------------------------- 1 | package uk.org.lidalia.sysoutslf4j.system; 2 | 3 | import java.io.PrintStream; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | 8 | /* 9 | * Copyright (c) 2009-2012 Robert Elliot 10 | * All rights reserved. 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining 13 | * a copy of this software and associated documentation files (the 14 | * "Software"), to deal in the Software without restriction, including 15 | * without limitation the rights to use, copy, modify, merge, publish, 16 | * distribute, sublicense, and/or sell copies of the Software, and to 17 | * permit persons to whom the Software is furnished to do so, subject to 18 | * the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be 21 | * included in all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | */ 31 | 32 | public abstract class SysOutOverSLF4JTestCase { 33 | 34 | protected ClassLoader originalContextClassLoader; 35 | protected PrintStream SYS_OUT; 36 | protected PrintStream SYS_ERR; 37 | 38 | @Before 39 | public void storeOriginalSystemOutAndErr() { 40 | SYS_OUT = System.out; 41 | SYS_ERR = System.err; 42 | } 43 | 44 | @After 45 | public void restoreOriginalSystemOutAndErr() { 46 | System.setOut(SYS_OUT); 47 | System.setErr(SYS_ERR); 48 | } 49 | 50 | @Before 51 | public void storeOriginalContextClassLoader() { 52 | originalContextClassLoader = Thread.currentThread().getContextClassLoader(); 53 | } 54 | 55 | @After 56 | public void restoreOriginalContextClassLoader() { 57 | Thread.currentThread().setContextClassLoader(originalContextClassLoader); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /sysout-over-slf4j-system/src/test/java/uk/org/lidalia/sysoutslf4j/system/SystemOutputTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2012 Robert Elliot 3 | * All rights reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | package uk.org.lidalia.sysoutslf4j.system; 26 | 27 | import java.io.ByteArrayOutputStream; 28 | import java.io.PrintStream; 29 | 30 | import org.junit.Test; 31 | 32 | import static org.junit.Assert.assertEquals; 33 | 34 | public class SystemOutputTests extends SysOutOverSLF4JTestCase { 35 | 36 | @Test 37 | public void SYSOUTGetReturnsSysout() { 38 | PrintStream actual = SystemOutput.OUT.get(); 39 | assertEquals(System.out, actual); 40 | } 41 | 42 | @Test 43 | public void SYSERRGetReturnsSyserr() { 44 | PrintStream actual = SystemOutput.ERR.get(); 45 | assertEquals(System.err, actual); 46 | } 47 | 48 | @Test 49 | public void SYSOUTSetAltersSysout() { 50 | PrintStream expected = new PrintStream(new ByteArrayOutputStream()); 51 | SystemOutput.OUT.set(expected); 52 | assertEquals(expected, System.out); 53 | } 54 | 55 | @Test 56 | public void SYSERRSetAltersSyserr() { 57 | PrintStream expected = new PrintStream(new ByteArrayOutputStream()); 58 | SystemOutput.ERR.set(expected); 59 | assertEquals(expected, System.err); 60 | } 61 | 62 | @Test 63 | public void SYSOUTToString() { 64 | assertEquals("System.out", SystemOutput.OUT.toString()); 65 | } 66 | 67 | @Test 68 | public void SYSERRToString() { 69 | assertEquals("System.err", SystemOutput.ERR.toString()); 70 | } 71 | 72 | @Test 73 | public void valueOf() { 74 | assertEquals(SystemOutput.ERR, SystemOutput.valueOf("ERR")); 75 | } 76 | } 77 | --------------------------------------------------------------------------------