001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.classic; 015 016import static org.junit.Assert.assertTrue; 017import static org.junit.Assert.assertEquals; 018 019import java.io.ByteArrayInputStream; 020import java.io.ByteArrayOutputStream; 021import java.io.FileInputStream; 022import java.io.IOException; 023import java.io.ObjectOutputStream; 024import java.util.ArrayList; 025import java.util.List; 026 027import org.junit.After; 028import org.junit.Before; 029import org.junit.Test; 030import org.slf4j.LoggerFactory; 031 032import ch.qos.logback.classic.net.server.HardenedLoggingEventInputStream; 033import ch.qos.logback.core.net.HardenedObjectInputStream; 034import ch.qos.logback.core.testUtil.CoreTestConstants; 035 036public class LoggerSerializationTest { 037 038 static final String SERIALIZATION_PREFIX = CoreTestConstants.TEST_INPUT_PREFIX + "/serialization/"; 039 040 // force SLF4J initialization for subsequent Logger readResolce ooperaiton 041 org.slf4j.Logger unused = LoggerFactory.getLogger(this.getClass()); 042 LoggerContext lc; 043 Logger logger; 044 045 ByteArrayOutputStream bos; 046 ObjectOutputStream oos; 047 HardenedLoggingEventInputStream hardenedLoggingEventInputStream; 048 List<String> whitelist = new ArrayList<String>(); 049 050 @Before 051 public void setUp() throws Exception { 052 lc = new LoggerContext(); 053 lc.setName("testContext"); 054 logger = lc.getLogger(LoggerSerializationTest.class); 055 // create the byte output stream 056 bos = new ByteArrayOutputStream(); 057 oos = new ObjectOutputStream(bos); 058 whitelist.add(Foo.class.getName()); 059 } 060 061 @After 062 public void tearDown() throws Exception { 063 lc = null; 064 logger = null; 065 } 066 067 @Test 068 public void basicSerialization() throws IOException, ClassNotFoundException { 069 Foo foo = new Foo(logger); 070 foo.doFoo(); 071 Foo fooBack = writeAndRead(foo); 072 fooBack.doFoo(); 073 } 074 075 @Test 076 public void deepTreeSerialization() throws IOException { 077 // crate a tree of loggers under "aaaaaaaa" 078 Logger a = lc.getLogger("aaaaaaaa"); 079 lc.getLogger("aaaaaaaa.a"); 080 lc.getLogger("aaaaaaaa.a.a"); 081 lc.getLogger("aaaaaaaa.a.b"); 082 lc.getLogger("aaaaaaaa.a.c"); 083 lc.getLogger("aaaaaaaa.a.d"); 084 085 lc.getLogger("aaaaaaaa.b"); 086 lc.getLogger("aaaaaaaa.b.a"); 087 lc.getLogger("aaaaaaaa.b.b"); 088 lc.getLogger("aaaaaaaa.b.c"); 089 lc.getLogger("aaaaaaaa.b.d"); 090 091 lc.getLogger("aaaaaaaa.c"); 092 lc.getLogger("aaaaaaaa.c.a"); 093 lc.getLogger("aaaaaaaa.c.b"); 094 lc.getLogger("aaaaaaaa.c.c"); 095 lc.getLogger("aaaaaaaa.c.d"); 096 097 lc.getLogger("aaaaaaaa.d"); 098 lc.getLogger("aaaaaaaa.d.a"); 099 lc.getLogger("aaaaaaaa.d.b"); 100 lc.getLogger("aaaaaaaa.d.c"); 101 lc.getLogger("aaaaaaaa.d.d"); 102 103 Logger b = lc.getLogger("b"); 104 105 writeObject(oos, a); 106 oos.close(); 107 int sizeA = bos.size(); 108 109 bos = new ByteArrayOutputStream(); 110 oos = new ObjectOutputStream(bos); 111 112 writeObject(oos, b); 113 oos.close(); 114 int sizeB = bos.size(); 115 116 assertTrue("serialized logger should be less than 100 bytes", sizeA < 100); 117 // logger tree should not influnce serialization 118 assertTrue("serialized loggers should be nearly the same size a:" + sizeA + ", sizeB:" + sizeB, (sizeA - sizeB) < 10); 119 } 120 121 private Foo writeAndRead(Foo foo) throws IOException, ClassNotFoundException { 122 writeObject(oos, foo); 123 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 124 hardenedLoggingEventInputStream = new HardenedLoggingEventInputStream(bis, whitelist); 125 Foo fooBack = readFooObject(hardenedLoggingEventInputStream); 126 hardenedLoggingEventInputStream.close(); 127 return fooBack; 128 } 129 130 Foo readFooObject(HardenedObjectInputStream inputStream) throws IOException, ClassNotFoundException { 131 return (Foo) readObject(inputStream); 132 } 133 134 private Object readObject(HardenedObjectInputStream inputStream) throws IOException, ClassNotFoundException { 135 return inputStream.readObject(); 136 } 137 138 private void writeObject(ObjectOutputStream oos, Object o) throws IOException { 139 oos.writeObject(o); 140 oos.flush(); 141 oos.close(); 142 } 143 144 @Test 145 public void testCompatibilityWith_v1_0_11() throws IOException, ClassNotFoundException { 146 FileInputStream fis = new FileInputStream(SERIALIZATION_PREFIX + "logger_v1.0.11.ser"); 147 HardenedObjectInputStream ois = new HardenedLoggingEventInputStream(fis); // new String[] {Logger.class.getName(), LoggerRemoteView.class.getName()}); 148 Logger a = (Logger) ois.readObject(); 149 ois.close(); 150 assertEquals("a", a.getName()); 151 } 152 153 // interestingly enough, logback 1.0.11 and earlier can also read loggers serialized by 1.0.12. 154 // fields not serialized are set to their default values and since the fields are not 155 // used, it works out nicely 156 @Test 157 public void testCompatibilityWith_v1_0_12() throws IOException, ClassNotFoundException { 158 FileInputStream fis = new FileInputStream(SERIALIZATION_PREFIX + "logger_v1.0.12.ser"); 159 HardenedObjectInputStream ois = new HardenedObjectInputStream(fis, new String[] {Logger.class.getName()}); 160 Logger a = (Logger) ois.readObject(); 161 ois.close(); 162 assertEquals("a", a.getName()); 163 } 164 165}