/*
 * Copyright 2012 Chris Vest
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package stormpot.examples;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.TimeUnit;

import javax.sql.DataSource;

import stormpot.Allocator;
import stormpot.Config;
import stormpot.LifecycledPool;
import stormpot.Poolable;
import stormpot.Slot;
import stormpot.Timeout;
import stormpot.qpool.QueuePool;

public class DaoPoolExample {
  static class MyDao implements Poolable {
    private final Slot slot;
    private final Connection connection;
    
    private MyDao(Slot slot, Connection connection) {
      this.slot = slot;
      this.connection = connection;
    }

    public void release() {
      slot.release(this);
    }

    private void close() throws SQLException {
      connection.close();
    }
    
    // ...
    // public DAO-type methods
    // ...
    
    public String getFirstName() {
      // Stub: get the name from the database using the connection.
      // But for now, just always return "freddy"
      return "freddy";
    }
  }
  
  static class MyDaoAllocator implements Allocator<MyDao> {
    private final DataSource dataSource;
    
    public MyDaoAllocator(DataSource dataSource) {
      this.dataSource = dataSource;
    }

    public MyDao allocate(Slot slot) throws Exception {
      synchronized (dataSource) {
        return new MyDao(slot, dataSource.getConnection());
      }
    }

    public void deallocate(MyDao poolable) throws Exception {
      poolable.close();
    }
  }
  
  static class MyDaoPool {
    private final LifecycledPool<MyDao> pool;
    
    public MyDaoPool(DataSource dataSource) {
      MyDaoAllocator allocator = new MyDaoAllocator(dataSource);
      Config<MyDao> config = new Config<MyDao>().setAllocator(allocator);
      pool = new QueuePool<MyDao>(config);
    }

    public void close() throws InterruptedException {
      pool.shutdown().await(new Timeout(1, TimeUnit.MINUTES));
    }
    
    public <T> T doWithDao(WithMyDaoDo<T> action)
    throws InterruptedException {
      MyDao dao = pool.claim(new Timeout(1, TimeUnit.SECONDS));
      try {
        return action.doWithDao(dao);
      } finally {
        dao.release();
      }
    }
  }
  
  static interface WithMyDaoDo<T> {
    public T doWithDao(MyDao dao);
  }
  
  public static void main(String[] args) throws InterruptedException {
    DataSource dataSource = configureDataSource();
    MyDaoPool pool = new MyDaoPool(dataSource);
    try {
      String person = pool.doWithDao(new WithMyDaoDo<String>() {
        public String doWithDao(MyDao dao) {
          return dao.getFirstName();
        }
      });
      System.out.println("Hello there, " + person + "!");
    } finally {
      pool.close();
    }
  }

  private static DataSource configureDataSource() {
    // Stub: configure and return some kind of DataSource object.
    // Allocation will fail with a NullPointerException until this method
    // get a proper implementation.
    return null;
  }
}

@@ -673,24 +673,51 @@
 LException;%0A
+import java.sql.Statement;%0A
 import java.
@@ -742,16 +742,16 @@
 meUnit;%0A
-
 %0Aimport 
@@ -824,16 +824,44 @@
 Config;%0A
+import stormpot.Expiration;%0A
 import s
@@ -932,16 +932,42 @@
 t.Slot;%0A
+import stormpot.SlotInfo;%0A
 import s
@@ -2134,32 +2134,626 @@
 );%0A    %7D%0A  %7D%0A  %0A
+  static class TestQueryExpiration implements Expiration%3CMyDao%3E %7B%0A    @Override%0A    public boolean hasExpired(SlotInfo%3C? extends MyDao%3E info) %7B%0A      Connection con = info.getPoolable().connection;%0A      Statement stmt = null;%0A      synchronized (con) %7B%0A        try %7B%0A          try %7B%0A            stmt = con.createStatement();%0A            stmt.execute(%22select 1 from dual;%22);%0A          %7D finally %7B%0A            if (stmt != null) %7B%0A              stmt.close();%0A            %7D%0A          %7D%0A        %7D catch (SQLException e) %7B%0A          return true;%0A        %7D%0A        return false;%0A      %7D%0A    %7D%0A  %7D%0A  %0A
   static class M
@@ -2999,16 +2999,71 @@
 cator);%0A
+      config.setExpiration(new TestQueryExpiration());%0A
       po
@@ -3282,16 +3282,20 @@
 action)%0A
+    
     thro

Add Expiration to the DaoPoolExample.