diff --git a/lesson-demo/src/main/java/com/bobocode/DemoApp.java b/lesson-demo/src/main/java/com/bobocode/DemoApp.java
index e937300d..cafa53f7 100644
--- a/lesson-demo/src/main/java/com/bobocode/DemoApp.java
+++ b/lesson-demo/src/main/java/com/bobocode/DemoApp.java
@@ -1,9 +1,10 @@
 package com.bobocode;
 
+import com.bobocode.pool.PooledDataSource;
 import lombok.SneakyThrows;
-import org.postgresql.ds.PGSimpleDataSource;
 
 import javax.sql.DataSource;
+import java.sql.SQLException;
 
 public class DemoApp {
     @SneakyThrows
@@ -24,23 +25,11 @@ public static void main(String[] args) {
         }
         System.out.println((System.nanoTime() - start) / 1000_000 + " ms");
         System.out.println(total);
-
-
-    }
-
-    private static DataSource initializeDataSource() {
-        PGSimpleDataSource dataSource = new PGSimpleDataSource();
-        dataSource.setURL("jdbc:postgresql://localhost:5432/postgres");
-        dataSource.setUser("ju22user");
-        dataSource.setPassword("ju22pass");
-        return dataSource;
     }
 
-    private static DataSource initializePooledDataSource() {
-        PGSimpleDataSource dataSource = new PGSimpleDataSource();
-        dataSource.setURL("jdbc:postgresql://localhost:5432/postgres");
-        dataSource.setUser("ju22user");
-        dataSource.setPassword("ju22pass");
-        return dataSource;
+    private static DataSource initializePooledDataSource() throws SQLException, InterruptedException {
+        return new PooledDataSource("jdbc:postgresql://localhost:5432/postgres",
+                "postgres",
+                "root");
     }
 }
diff --git a/lesson-demo/src/main/java/com/bobocode/pool/ConnectionProxy.java b/lesson-demo/src/main/java/com/bobocode/pool/ConnectionProxy.java
index 06461956..3add39e7 100644
--- a/lesson-demo/src/main/java/com/bobocode/pool/ConnectionProxy.java
+++ b/lesson-demo/src/main/java/com/bobocode/pool/ConnectionProxy.java
@@ -1,8 +1,332 @@
 package com.bobocode.pool;
 
-public class ConnectionProxy {
-    // todo: 1. store a physical connection and a pool reference
-    // todo: 2. override method close
-    // todo: 3. delegate all method invocations to a physical connection
-    
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.CallableStatement;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.SQLClientInfoException;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Savepoint;
+import java.sql.ShardingKey;
+import java.sql.Statement;
+import java.sql.Struct;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Queue;
+import java.util.concurrent.Executor;
+
+public class ConnectionProxy implements Connection {
+    private final Connection connection;
+    private final Queue<Connection> pool;
+
+    public ConnectionProxy(Connection connection, Queue<Connection> pool) {
+        this.connection = connection;
+        this.pool = pool;
+    }
+
+    @Override
+    public Statement createStatement() throws SQLException {
+        return connection.createStatement();
+    }
+
+    @Override
+    public PreparedStatement prepareStatement(String sql) throws SQLException {
+        return connection.prepareStatement(sql);
+    }
+
+    @Override
+    public CallableStatement prepareCall(String sql) throws SQLException {
+        return connection.prepareCall(sql);
+    }
+
+    @Override
+    public String nativeSQL(String sql) throws SQLException {
+        return connection.nativeSQL(sql);
+    }
+
+    @Override
+    public void setAutoCommit(boolean autoCommit) throws SQLException {
+        connection.setAutoCommit(autoCommit);
+    }
+
+    @Override
+    public boolean getAutoCommit() throws SQLException {
+        return connection.getAutoCommit();
+    }
+
+    @Override
+    public void commit() throws SQLException {
+        connection.commit();
+    }
+
+    @Override
+    public void rollback() throws SQLException {
+        connection.rollback();
+    }
+
+    @Override
+    public void close() throws SQLException {
+        pool.add(this);
+    }
+
+    @Override
+    public boolean isClosed() throws SQLException {
+        return connection.isClosed();
+    }
+
+    @Override
+    public DatabaseMetaData getMetaData() throws SQLException {
+        return connection.getMetaData();
+    }
+
+    @Override
+    public void setReadOnly(boolean readOnly) throws SQLException {
+        connection.setReadOnly(readOnly);
+    }
+
+    @Override
+    public boolean isReadOnly() throws SQLException {
+        return connection.isReadOnly();
+    }
+
+    @Override
+    public void setCatalog(String catalog) throws SQLException {
+        connection.setCatalog(catalog);
+    }
+
+    @Override
+    public String getCatalog() throws SQLException {
+        return connection.getCatalog();
+    }
+
+    @Override
+    public void setTransactionIsolation(int level) throws SQLException {
+        connection.setTransactionIsolation(level);
+    }
+
+    @Override
+    public int getTransactionIsolation() throws SQLException {
+        return connection.getTransactionIsolation();
+    }
+
+    @Override
+    public SQLWarning getWarnings() throws SQLException {
+        return connection.getWarnings();
+    }
+
+    @Override
+    public void clearWarnings() throws SQLException {
+        connection.clearWarnings();
+    }
+
+    @Override
+    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
+        return connection.createStatement(resultSetType, resultSetConcurrency);
+    }
+
+    @Override
+    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+        return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
+    }
+
+    @Override
+    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+        return connection.prepareCall(sql, resultSetType, resultSetConcurrency);
+    }
+
+    @Override
+    public Map<String, Class<?>> getTypeMap() throws SQLException {
+        return connection.getTypeMap();
+    }
+
+    @Override
+    public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
+        connection.setTypeMap(map);
+    }
+
+    @Override
+    public void setHoldability(int holdability) throws SQLException {
+        connection.setHoldability(holdability);
+    }
+
+    @Override
+    public int getHoldability() throws SQLException {
+        return connection.getHoldability();
+    }
+
+    @Override
+    public Savepoint setSavepoint() throws SQLException {
+        return connection.setSavepoint();
+    }
+
+    @Override
+    public Savepoint setSavepoint(String name) throws SQLException {
+        return connection.setSavepoint(name);
+    }
+
+    @Override
+    public void rollback(Savepoint savepoint) throws SQLException {
+        connection.rollback(savepoint);
+    }
+
+    @Override
+    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
+        connection.releaseSavepoint(savepoint);
+    }
+
+    @Override
+    public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+        return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
+    }
+
+    @Override
+    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+        return connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
+    }
+
+    @Override
+    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+        return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
+    }
+
+    @Override
+    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
+        return connection.prepareStatement(sql, autoGeneratedKeys);
+    }
+
+    @Override
+    public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
+        return connection.prepareStatement(sql, columnIndexes);
+    }
+
+    @Override
+    public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
+        return connection.prepareStatement(sql, columnNames);
+    }
+
+    @Override
+    public Clob createClob() throws SQLException {
+        return connection.createClob();
+    }
+
+    @Override
+    public Blob createBlob() throws SQLException {
+        return connection.createBlob();
+    }
+
+    @Override
+    public NClob createNClob() throws SQLException {
+        return connection.createNClob();
+    }
+
+    @Override
+    public SQLXML createSQLXML() throws SQLException {
+        return connection.createSQLXML();
+    }
+
+    @Override
+    public boolean isValid(int timeout) throws SQLException {
+        return connection.isValid(timeout);
+    }
+
+    @Override
+    public void setClientInfo(String name, String value) throws SQLClientInfoException {
+        connection.setClientInfo(name, value);
+    }
+
+    @Override
+    public void setClientInfo(Properties properties) throws SQLClientInfoException {
+        connection.setClientInfo(properties);
+    }
+
+    @Override
+    public String getClientInfo(String name) throws SQLException {
+        return connection.getClientInfo(name);
+    }
+
+    @Override
+    public Properties getClientInfo() throws SQLException {
+        return connection.getClientInfo();
+    }
+
+    @Override
+    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
+        return connection.createArrayOf(typeName, elements);
+    }
+
+    @Override
+    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
+        return connection.createStruct(typeName, attributes);
+    }
+
+    @Override
+    public void setSchema(String schema) throws SQLException {
+        connection.setSchema(schema);
+    }
+
+    @Override
+    public String getSchema() throws SQLException {
+        return connection.getSchema();
+    }
+
+    @Override
+    public void abort(Executor executor) throws SQLException {
+        connection.abort(executor);
+    }
+
+    @Override
+    public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
+        connection.setNetworkTimeout(executor, milliseconds);
+    }
+
+    @Override
+    public int getNetworkTimeout() throws SQLException {
+        return connection.getNetworkTimeout();
+    }
+
+    @Override
+    public void beginRequest() throws SQLException {
+        connection.beginRequest();
+    }
+
+    @Override
+    public void endRequest() throws SQLException {
+        connection.endRequest();
+    }
+
+    @Override
+    public boolean setShardingKeyIfValid(ShardingKey shardingKey, ShardingKey superShardingKey, int timeout) throws SQLException {
+        return connection.setShardingKeyIfValid(shardingKey, superShardingKey, timeout);
+    }
+
+    @Override
+    public boolean setShardingKeyIfValid(ShardingKey shardingKey, int timeout) throws SQLException {
+        return connection.setShardingKeyIfValid(shardingKey, timeout);
+    }
+
+    @Override
+    public void setShardingKey(ShardingKey shardingKey, ShardingKey superShardingKey) throws SQLException {
+        connection.setShardingKey(shardingKey, superShardingKey);
+    }
+
+    @Override
+    public void setShardingKey(ShardingKey shardingKey) throws SQLException {
+        connection.setShardingKey(shardingKey);
+    }
+
+    @Override
+    public <T> T unwrap(Class<T> iface) throws SQLException {
+        return connection.unwrap(iface);
+    }
+
+    @Override
+    public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        return connection.isWrapperFor(iface);
+    }
 }
diff --git a/lesson-demo/src/main/java/com/bobocode/pool/PooledDataSource.java b/lesson-demo/src/main/java/com/bobocode/pool/PooledDataSource.java
index 92f72068..1b563030 100644
--- a/lesson-demo/src/main/java/com/bobocode/pool/PooledDataSource.java
+++ b/lesson-demo/src/main/java/com/bobocode/pool/PooledDataSource.java
@@ -1,9 +1,35 @@
 package com.bobocode.pool;
 
+import lombok.SneakyThrows;
 import org.postgresql.ds.PGSimpleDataSource;
 
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
 public class PooledDataSource extends PGSimpleDataSource {
-    // todo: 1. store a queue of connections (this is a pool)
-    // todo: 2. initialize a datasource with 10 physical connection
-    // todo: 3. override method getConnection so it uses a pool
+    private Queue<Connection> pool;
+    private final int poolSize = 10;
+
+    public PooledDataSource(String url, String userName, String pass) {
+        this.pool = new ConcurrentLinkedQueue<>();
+        this.setUrl(url);
+        this.setUser(userName);
+        this.setPassword(pass);
+        initPool();
+    }
+
+    @SneakyThrows
+    private void initPool() {
+        for (int i = 0; i < poolSize; i++) {
+            Connection connection = super.getConnection();
+            pool.add(new ConnectionProxy(connection, pool));
+        }
+    }
+
+    @Override
+    public Connection getConnection() throws SQLException {
+        return pool.poll();
+    }
 }