View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.pool2.proxy;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertNotNull;
21  import static org.junit.jupiter.api.Assertions.assertThrows;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.io.PrintWriter;
25  import java.io.StringWriter;
26  import java.time.Duration;
27  
28  import org.apache.commons.pool2.BasePooledObjectFactory;
29  import org.apache.commons.pool2.ObjectPool;
30  import org.apache.commons.pool2.PooledObject;
31  import org.apache.commons.pool2.PooledObjectFactory;
32  import org.apache.commons.pool2.impl.AbandonedConfig;
33  import org.apache.commons.pool2.impl.DefaultPooledObject;
34  import org.apache.commons.pool2.impl.GenericObjectPool;
35  import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
36  import org.junit.jupiter.api.BeforeEach;
37  import org.junit.jupiter.api.Test;
38  
39  
40  public abstract class AbstractTestProxiedObjectPool {
41  
42      protected interface TestObject {
43          String getData();
44          void setData(String data);
45      }
46      private static class TestObjectFactory extends
47              BasePooledObjectFactory<TestObject> {
48  
49          @Override
50          public TestObject create() {
51              return new TestObjectImpl();
52          }
53          @Override
54          public PooledObject<TestObject> wrap(final TestObject value) {
55              return new DefaultPooledObject<>(value);
56          }
57      }
58  
59      private static class TestObjectImpl implements TestObject {
60  
61          private String data;
62  
63          @Override
64          public String getData() {
65              return data;
66          }
67  
68          @Override
69          public void setData(final String data) {
70              this.data = data;
71          }
72      }
73      private static final String DATA1 = "data1";
74  
75      private static final Duration ABANDONED_TIMEOUT_SECS = Duration.ofSeconds(3);
76  
77  
78      private ObjectPool<TestObject> pool;
79  
80      private StringWriter log;
81  
82  
83      protected abstract ProxySource<TestObject> getproxySource();
84  
85  
86      @BeforeEach
87      public void setUp() {
88          log = new StringWriter();
89  
90          final PrintWriter pw = new PrintWriter(log);
91          final AbandonedConfig abandonedConfig = new AbandonedConfig();
92          abandonedConfig.setLogAbandoned(true);
93          abandonedConfig.setRemoveAbandonedOnBorrow(true);
94          abandonedConfig.setUseUsageTracking(true);
95          abandonedConfig.setRemoveAbandonedTimeout(ABANDONED_TIMEOUT_SECS);
96          abandonedConfig.setLogWriter(pw);
97  
98          final GenericObjectPoolConfig<TestObject> config = new GenericObjectPoolConfig<>();
99          config.setMaxTotal(3);
100 
101         final PooledObjectFactory<TestObject> factory = new TestObjectFactory();
102 
103         @SuppressWarnings("resource")
104         final ObjectPool<TestObject> innerPool = new GenericObjectPool<>(factory, config, abandonedConfig);
105 
106         pool = new ProxiedObjectPool<>(innerPool, getproxySource());
107     }
108 
109 
110     @Test
111     public void testAccessAfterInvalidate() throws Exception {
112         final TestObject obj = pool.borrowObject();
113         assertNotNull(obj);
114 
115         // Make sure proxied methods are working
116         obj.setData(DATA1);
117         assertEquals(DATA1, obj.getData());
118 
119         pool.invalidateObject(obj);
120 
121         assertNotNull(obj);
122 
123         assertThrows(IllegalStateException.class,
124                 obj::getData);
125 
126     }
127 
128 
129     @Test
130     public void testAccessAfterReturn() throws Exception {
131         final TestObject obj = pool.borrowObject();
132         assertNotNull(obj);
133 
134         // Make sure proxied methods are working
135         obj.setData(DATA1);
136         assertEquals(DATA1, obj.getData());
137 
138         pool.returnObject(obj);
139 
140         assertNotNull(obj);
141 
142         assertThrows(IllegalStateException.class,
143                 obj::getData);
144     }
145 
146 
147     @Test
148     public void testBorrowObject() throws Exception {
149         final TestObject obj = pool.borrowObject();
150         assertNotNull(obj);
151 
152         // Make sure proxied methods are working
153         obj.setData(DATA1);
154         assertEquals(DATA1, obj.getData());
155 
156         pool.returnObject(obj);
157     }
158 
159     @Test
160     public void testPassThroughMethods01() throws Exception {
161         assertEquals(0, pool.getNumActive());
162         assertEquals(0, pool.getNumIdle());
163 
164         pool.addObject();
165 
166         assertEquals(0, pool.getNumActive());
167         assertEquals(1, pool.getNumIdle());
168 
169         pool.clear();
170 
171         assertEquals(0, pool.getNumActive());
172         assertEquals(0, pool.getNumIdle());
173     }
174 
175 
176     @Test
177     public void testPassThroughMethods02() {
178         pool.close();
179 
180         assertThrows(IllegalStateException.class,
181                 () -> pool.addObject());
182     }
183 
184 
185     @Test
186     public void testUsageTracking() throws Exception {
187         final TestObject obj = pool.borrowObject();
188         assertNotNull(obj);
189 
190         // Use the object to trigger collection of last used stack trace
191         obj.setData(DATA1);
192 
193         // Sleep long enough for the object to be considered abandoned
194         Thread.sleep(ABANDONED_TIMEOUT_SECS.plusSeconds(2).toMillis());
195 
196         // Borrow another object to trigger the abandoned object processing
197         pool.borrowObject();
198 
199         final String logOutput = log.getBuffer().toString();
200 
201         assertTrue(logOutput.contains("Pooled object created"));
202         assertTrue(logOutput.contains("The last code to use this object was"));
203     }
204 
205 }