package lecture.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import lecture.common.DB;
import lecture.common.Log;

/**
 *  DAOをテンプレートパターンで実装したサンプル Java
 *
 *  サンプルなので、DAO、Entity、テストプログラムを一つのJavaファイルに実装しているが、
 *  実際は別のファイルに記述する
 */
class DaoTemplate {
  private static final String isbn0 = "8888";
  private static final String isbn1 = "7777";
  public static void main(String[] args) throws SQLException {
    Connection conn = null;
    try {
      conn = DB.get();
      BookDao dao = new BookDao(conn);
      // レコードの挿入
      BookEntity entity = new BookEntity();
      entity.setIsbn(isbn0);
      entity.setName("Javaのすばらしい本");
      entity.setPrice(5000);
      dao.insert(entity);
      //
      entity = new BookEntity();
      entity.setIsbn(isbn1);
      entity.setName("Javaの普通の本");
      entity.setPrice(4000);
      dao.insert(entity);
      //
      // レコードの検索
      entity = dao.getEntity(isbn0);
      Log.print(entity.toString());
      entity = dao.getEntity(isbn1);
      Log.print(entity.toString());
      //
      // レコードの削除
      dao.delete(isbn0);
      dao.delete(isbn1);
    }
    catch(Exception ex) {
      ex.printStackTrace();
    }
    finally {
      DB.close(conn);
    }
  }

  /** 書籍DAO */
  static class BookDao {
    private Connection conn;
    public BookDao(Connection conn) {
      this.conn = conn;
    }
    public int insert(final BookEntity entity) throws SQLException {
      ExecuteTemplate tmp = new ExecuteTemplate(conn) {
        public String getSql() {
          return "insert into BOOK (ISBN,NAME,PRICE) values (?,?,?)";
        }
        public void setParameter(PreparedStatement st) throws SQLException {
          st.setString(1,entity.getIsbn());
          st.setString(2,entity.getName());
          st.setInt(3,entity.getPrice());
        }
      };
      return tmp.go();
    }
    public int delete(final String isbn) throws SQLException {
      ExecuteTemplate tmp = new ExecuteTemplate(conn) {
        public String getSql() {
          return "delete from BOOK where ISBN=?";
        }
        public void setParameter(PreparedStatement st) throws SQLException {
          st.setString(1,isbn);
        }
      };
      return tmp.go();
    }
    public BookEntity getEntity(final String isbn) throws SQLException {
      SearchTemplate tmp = new SearchTemplate(conn) {
        public String getSql() {
          return "select ISBN,NAME,PRICE from BOOK where ISBN=?";
        }
        public void setParameter(PreparedStatement st) throws SQLException {
          st.setString(1,isbn);
        }
        public Object createObject(ResultSet rs) throws SQLException {
          BookEntity entity = new BookEntity();
          entity.setIsbn(rs.getString("ISBN"));
          entity.setName(rs.getString("NAME"));
          entity.setPrice(rs.getInt("PRICE"));
          return entity;
        }
      };
      return (BookEntity)tmp.go();
    }
  }
  /** 更新系DAOテンプレート */
  static abstract class ExecuteTemplate {
    private Connection conn;
    public ExecuteTemplate(Connection conn) {
      this.conn = conn;
    }
    public int go() throws SQLException {
      PreparedStatement st = null;
      try {
        String sql = getSql();
        st = conn.prepareStatement(sql);
        setParameter(st);
        return st.executeUpdate();
      }
      finally {
        DB.close(st);
      }
    }
    // 呼び出す側で指定するメソッド
    abstract public String getSql();
    abstract public void setParameter(PreparedStatement st) throws SQLException;
  }
  /** 検索系DAOテンプレート */
  static abstract class SearchTemplate {
    private Connection conn;
    public SearchTemplate(Connection conn) {
      this.conn = conn;
    }
    public Object go() throws SQLException {
      PreparedStatement st = null;
      ResultSet rs = null;
      try {
        String sql = getSql();
        st = conn.prepareStatement(sql);
        setParameter(st);
        rs = st.executeQuery();
        rs.next();
        return createObject(rs);
      }
      finally {
        DB.close(rs);
        DB.close(st);
      }
    }
    // 呼び出す側で指定するメソッド
    abstract public String getSql();
    abstract public void setParameter(PreparedStatement st) throws SQLException;
    abstract public Object createObject(ResultSet rs) throws SQLException;
  }
  /** 書籍Entity */
  static class BookEntity {
    private String isbn;
    private String name;
    private int price;
    public String getIsbn() {
    return isbn;
    }
    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getPrice() {
        return price;
    }
    public void setPrice(int price) {
        this.price = price;
    }
    public String toString() {
      return "isbn="+isbn+":name="+name+":price="+price;
    }
  }
}
//---------------------------------------------------
//・目次 - JDBC
//  http://blogs.yahoo.co.jp/artery2020/40575568.html
//・目次 - Java入門
//  http://blogs.yahoo.co.jp/artery2020/39975776.html
//・目次 - ビジネスパーソンの常識と非常識
//  http://blogs.yahoo.co.jp/artery2020/39728331.html
//・目次 - 論理・発想・思考についての考察と鍛え方
//  http://blogs.yahoo.co.jp/artery2020/39657784.html
//・目次 - 単なる雑談
//  http://blogs.yahoo.co.jp/artery2020/40599073.html
//---------------------------------------------------