Package cn.edu.zju.acm.onlinejudge.persistence.sql

Source Code of cn.edu.zju.acm.onlinejudge.persistence.sql.ProblemPersistenceImpl

/*
* Copyright 2007 Zhang, Zheng <oldbig@gmail.com> Xu, Chuan <xuchuan@gmail.com>
*
* This file is part of ZOJ.
*
* ZOJ is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either revision 3 of the License, or (at your option) any later revision.
*
* ZOJ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with ZOJ. if not, see
* <http://www.gnu.org/licenses/>.
*/

package cn.edu.zju.acm.onlinejudge.persistence.sql;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import cn.edu.zju.acm.onlinejudge.bean.Limit;
import cn.edu.zju.acm.onlinejudge.bean.Problem;
import cn.edu.zju.acm.onlinejudge.bean.request.ProblemCriteria;
import cn.edu.zju.acm.onlinejudge.persistence.PersistenceException;
import cn.edu.zju.acm.onlinejudge.persistence.ProblemPersistence;

/**
* <p>
* ProblemPersistenceImpl implements ProblemPersistence interface
* </p>
* <p>
* ProblemPersistence interface defines the API used to manager the problem related affairs in persistence layer.
* </p>
*
* @version 2.0
* @author Zhang, Zheng
* @author Xu, Chuan
*/
public class ProblemPersistenceImpl implements ProblemPersistence {

    /**
     * The default limit id.
     */
    private static final long DEFAULT_LIMIT_ID = 1;

    /**
     * The statement to get the contest limit id.
     */
    private static final String GET_CONTEST_LIMIT_ID =
            MessageFormat
                         .format("SELECT {0} FROM {1} WHERE {2}=?", new Object[] {DatabaseConstants.CONTEST_LIMITS_ID,
                                                                                  DatabaseConstants.CONTEST_TABLE,
                                                                                  DatabaseConstants.CONTEST_CONTEST_ID});

    /**
     * The statement to create a Problem.
     */
    private static final String INSERT_PROBLEM =
            MessageFormat.format(
                                 "INSERT INTO {0} ({1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}, {14}, {15}, {16})"
                                     + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)",
                                 new Object[] {DatabaseConstants.PROBLEM_TABLE, DatabaseConstants.PROBLEM_CONTEST_ID,
                                               DatabaseConstants.PROBLEM_TITLE, DatabaseConstants.PROBLEM_CODE,
                                               DatabaseConstants.PROBLEM_LIMITS_ID, DatabaseConstants.PROBLEM_AUTHOR,
                                               DatabaseConstants.PROBLEM_SOURCE, DatabaseConstants.PROBLEM_CONTEST,
                                               DatabaseConstants.PROBLEM_CHECKER, DatabaseConstants.PROBLEM_REVISION,
                                               DatabaseConstants.CREATE_USER, DatabaseConstants.CREATE_DATE,
                                               DatabaseConstants.LAST_UPDATE_USER, DatabaseConstants.LAST_UPDATE_DATE,
                                               DatabaseConstants.CONTEST_ACTIVE, DatabaseConstants.PROBLEM_COLOR,
                                               DatabaseConstants.PROBLEM_SCORE});

    /**
     * The statement to update a Problem.
     */
    private static final String UPDATE_PROBLEM =
            MessageFormat.format("UPDATE {0} SET {1}=?, {2}=?, {3}=?, {4}=?, {5}=?, {6}=?, {7}=?, {8}=?, "
                + "{9}={9}+1, {10}=?, {11}=?, {12}={12}+1, {13}=?, {15}=? WHERE {14}=?",
                                 new Object[] {DatabaseConstants.PROBLEM_TABLE,
                                 DatabaseConstants.PROBLEM_CONTEST_ID,
                                               DatabaseConstants.PROBLEM_TITLE,
                                               DatabaseConstants.PROBLEM_CODE,
                                               DatabaseConstants.PROBLEM_LIMITS_ID,
                                               DatabaseConstants.PROBLEM_AUTHOR,
                                               DatabaseConstants.PROBLEM_SOURCE,
                                               DatabaseConstants.PROBLEM_CONTEST,
                                               DatabaseConstants.PROBLEM_CHECKER,
                                               DatabaseConstants.PROBLEM_REVISION,
                                               DatabaseConstants.LAST_UPDATE_USER,
                                               DatabaseConstants.LAST_UPDATE_DATE,
                                               DatabaseConstants.PROBLEM_REVISION,
                                               DatabaseConstants.PROBLEM_COLOR,
                                               DatabaseConstants.PROBLEM_PROBLEM_ID,
                                               DatabaseConstants.PROBLEM_SCORE});

    /**
     * The statement to delete a problem.
     */
    private static final String DELETE_PROBLEM =
            MessageFormat.format("UPDATE {0} SET {1}=CONCAT({2}, {1}), {3}=CONCAT({2}, {3}), "
                + "{4}=0, {5}=?, {6}=? WHERE {2}=?", new Object[] {DatabaseConstants.PROBLEM_TABLE,
                                                                   DatabaseConstants.PROBLEM_TITLE,
                                                                   DatabaseConstants.PROBLEM_PROBLEM_ID,
                                                                   DatabaseConstants.PROBLEM_CODE,
                                                                   DatabaseConstants.PROBLEM_ACTIVE,
                                                                   DatabaseConstants.LAST_UPDATE_USER,
                                                                   DatabaseConstants.LAST_UPDATE_DATE});

    /**
     * The query to get a problem.
     */
    private static final String GET_PROBLEM =
            MessageFormat.format("SELECT {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {12}, {13} "
                + "FROM {10} WHERE {11}=1 AND {0}=?", new Object[] {DatabaseConstants.PROBLEM_PROBLEM_ID,
                                                                    DatabaseConstants.PROBLEM_CONTEST_ID,
                                                                    DatabaseConstants.PROBLEM_TITLE,
                                                                    DatabaseConstants.PROBLEM_CODE,
                                                                    DatabaseConstants.PROBLEM_LIMITS_ID,
                                                                    DatabaseConstants.PROBLEM_AUTHOR,
                                                                    DatabaseConstants.PROBLEM_SOURCE,
                                                                    DatabaseConstants.PROBLEM_CONTEST,
                                                                    DatabaseConstants.PROBLEM_CHECKER,
                                                                    DatabaseConstants.PROBLEM_REVISION,
                                                                    DatabaseConstants.PROBLEM_TABLE,
                                                                    DatabaseConstants.PROBLEM_ACTIVE,
                                                                    DatabaseConstants.PROBLEM_COLOR,
                                                                    DatabaseConstants.PROBLEM_SCORE});
    /*
     * The query to search problems.
     */
    private static final String SEARCH_PROBLEMS =
            MessageFormat.format(
                                 "SELECT {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, p.{9}, {10}, {11}, {12}, {13}, {17}, {18} "
                                     + "FROM {14} p LEFT JOIN {15} l ON p.{9} = l.{9} WHERE {16}=1 ",
                                 new Object[] {DatabaseConstants.PROBLEM_PROBLEM_ID,
                                               DatabaseConstants.PROBLEM_CONTEST_ID,
                                               DatabaseConstants.PROBLEM_TITLE,
                                               DatabaseConstants.PROBLEM_CODE,
                                               DatabaseConstants.PROBLEM_AUTHOR,
                                               DatabaseConstants.PROBLEM_SOURCE,
                                               DatabaseConstants.PROBLEM_CONTEST,
                                               DatabaseConstants.PROBLEM_CHECKER,
                                               DatabaseConstants.PROBLEM_REVISION,
                                               DatabaseConstants.PROBLEM_LIMITS_ID,
                                               DatabaseConstants.LIMITS_TIME_LIMIT,
                                               DatabaseConstants.LIMITS_MEMORY_LIMIT,
                                               DatabaseConstants.LIMITS_OUTPUT_LIMIT,
                                               DatabaseConstants.LIMITS_SUBMISSION_LIMIT,
                                               DatabaseConstants.PROBLEM_TABLE,
                                               DatabaseConstants.LIMITS_TABLE,
                                               DatabaseConstants.PROBLEM_ACTIVE,
                                               DatabaseConstants.PROBLEM_COLOR,
                                               DatabaseConstants.PROBLEM_SCORE});

    /**
     * The statement to create a Limit.
     */
    // TODO(xuchuan): move all these into a LimitPersistence class
    private static final String INSERT_LIMIT =
            MessageFormat.format("INSERT INTO {0} ({1}, {2}, {3}, {4}) VALUES(?, ?, ?, ?)",
                                 new Object[] {DatabaseConstants.LIMITS_TABLE, DatabaseConstants.LIMITS_TIME_LIMIT,
                                               DatabaseConstants.LIMITS_MEMORY_LIMIT,
                                               DatabaseConstants.LIMITS_OUTPUT_LIMIT,
                                               DatabaseConstants.LIMITS_SUBMISSION_LIMIT});

    /**
     * The query to get a limit.
     */
    private static final String GET_LIMIT =
            MessageFormat.format("SELECT {0}, {1}, {2}, {3}, {4} FROM {5} WHERE {0}=?",
                                 new Object[] {DatabaseConstants.LIMITS_LIMITS_ID, DatabaseConstants.LIMITS_TIME_LIMIT,
                                               DatabaseConstants.LIMITS_MEMORY_LIMIT,
                                               DatabaseConstants.LIMITS_OUTPUT_LIMIT,
                                               DatabaseConstants.LIMITS_SUBMISSION_LIMIT,
                                               DatabaseConstants.LIMITS_TABLE});

    /**
     * <p>
     * Creates the specified problem in persistence layer.
     * </p>
     *
     * @param problem
     *            the Problem instance to create
     * @param user
     *            the id of the user who made this modification
     * @throws PersistenceException
     *             wrapping a persistence implementation specific exception
     */
    public void createProblem(Problem problem, long user) throws PersistenceException {
        Connection conn = null;
        try {
            conn = Database.createConnection();
            conn.setAutoCommit(false);
            PreparedStatement ps = null;
            Limit limit;
            try {
                long contestLimitId = ProblemPersistenceImpl.DEFAULT_LIMIT_ID;
                ps = conn.prepareStatement(ProblemPersistenceImpl.GET_CONTEST_LIMIT_ID);
                ps.setLong(1, problem.getContestId());
                ResultSet rs = ps.executeQuery();
                if (rs.next()) {
                    contestLimitId = rs.getLong(1);
                }
                limit = problem.getLimit();
                if (limit == null) {
                    limit = new Limit();
                    limit.setId(contestLimitId);
                    problem.setLimit(limit);
                }
                if (limit.getId() != contestLimitId) {
                    ps = conn.prepareStatement(ProblemPersistenceImpl.INSERT_LIMIT);
                    ps.setInt(1, limit.getTimeLimit());
                    ps.setInt(2, limit.getMemoryLimit());
                    ps.setInt(3, limit.getOutputLimit());
                    ps.setInt(4, limit.getSubmissionLimit());
                    ps.executeUpdate();
                    limit.setId(Database.getLastId(conn));
                }
            } finally {
                Database.dispose(ps);
            }
            try {
                // create the problem
                ps = conn.prepareStatement(ProblemPersistenceImpl.INSERT_PROBLEM);
                ps.setLong(1, problem.getContestId());
                ps.setString(2, problem.getTitle());
                ps.setString(3, problem.getCode());
                ps.setLong(4, limit.getId());
                ps.setString(5, problem.getAuthor());
                ps.setString(6, problem.getSource());
                ps.setString(7, problem.getContest());
                ps.setBoolean(8, problem.isChecker());
                ps.setInt(9, 0);
                ps.setLong(10, user);
                ps.setTimestamp(11, new Timestamp(new Date().getTime()));
                ps.setLong(12, user);
                ps.setTimestamp(13, new Timestamp(new Date().getTime()));
                ps.setString(14, problem.getColor());
                ps.setInt(15, problem.getScore());
                ps.executeUpdate();
                problem.setId(Database.getLastId(conn));
            } finally {
                Database.dispose(ps);
            }
            conn.commit();
        } catch (Exception e) {
            Database.rollback(conn);
            throw new PersistenceException("Failed to create problem.", e);
        } finally {
            Database.dispose(conn);
        }
    }

    /**
     * <p>
     * Updates the specified problem in persistence layer.
     * </p>
     *
     * @param problem
     *            the Problem instance to update
     * @param user
     *            the id of the user who made this modification
     * @throws PersistenceException
     *             wrapping a persistence implementation specific exception
     */
    public void updateProblem(Problem problem, long user) throws PersistenceException {
        Connection conn = null;
        try {
            conn = Database.createConnection();
            conn.setAutoCommit(false);
            PreparedStatement ps = null;
            long contestLimitId = ProblemPersistenceImpl.DEFAULT_LIMIT_ID;
            try {
                ps = conn.prepareStatement(ProblemPersistenceImpl.GET_CONTEST_LIMIT_ID);
                ps.setLong(1, problem.getContestId());
                ResultSet rs = ps.executeQuery();
                if (rs.next()) {
                    contestLimitId = rs.getLong(1);
                }
            } finally {
                Database.dispose(ps);
            }
            // update a new limit
            Limit limit = problem.getLimit();
            if (limit.getId() != contestLimitId) {
                try {
                    ps = conn.prepareStatement(ProblemPersistenceImpl.INSERT_LIMIT);
                    ps.setInt(1, limit.getTimeLimit());
                    ps.setInt(2, limit.getMemoryLimit());
                    ps.setInt(3, limit.getOutputLimit());
                    ps.setInt(4, limit.getSubmissionLimit());
                    ps.executeUpdate();
                    limit.setId(Database.getLastId(conn));
                } finally {
                    Database.dispose(ps);
                }
            }
            try {
                // update the problem
                ps = conn.prepareStatement(ProblemPersistenceImpl.UPDATE_PROBLEM);
                ps.setLong(1, problem.getContestId());
                ps.setString(2, problem.getTitle());
                ps.setString(3, problem.getCode());
                ps.setLong(4, limit.getId());
                ps.setString(5, problem.getAuthor());
                ps.setString(6, problem.getSource());
                ps.setString(7, problem.getContest());
                ps.setBoolean(8, problem.isChecker());
                ps.setLong(9, user);
                ps.setTimestamp(10, new Timestamp(new Date().getTime()));
                ps.setString(11, problem.getColor());
                ps.setInt(12, problem.getScore());
                ps.setLong(13, problem.getId());
                ps.executeUpdate();
            } finally {
                Database.dispose(ps);
            }
            conn.commit();
        } catch (Exception e) {
            Database.rollback(conn);
            throw new PersistenceException("Failed to create problem.", e);
        } finally {
            Database.dispose(conn);
        }
    }

    /**
     * <p>
     * Deletes the specified problem in persistence layer.
     * </p>
     *
     * @param id
     *            the id of the problem to delete
     * @param user
     *            the id of the user who made this modification
     * @throws PersistenceException
     *             wrapping a persistence implementation specific exception
     */
    public void deleteProblem(long id, long user) throws PersistenceException {
        Connection conn = null;
        try {
            conn = Database.createConnection();
            PreparedStatement ps = null;
            try {
                ps = conn.prepareStatement(ProblemPersistenceImpl.DELETE_PROBLEM);
                ps.setLong(1, user);
                ps.setTimestamp(2, new Timestamp(new Date().getTime()));
                ps.setLong(3, id);
                if (ps.executeUpdate() == 0) {
                    throw new PersistenceException("no such problem");
                }
            } finally {
                Database.dispose(ps);
            }
        } catch (PersistenceException pe) {
            throw pe;
        } catch (Exception e) {
            throw new PersistenceException("Failed to delete contest.", e);
        } finally {
            Database.dispose(conn);
        }
    }

    /**
     * <p>
     * Gets the problem with given id in persistence layer.
     * </p>
     *
     * @param id
     *            the id of the problem
     * @return the problem with given id in persistence layer
     * @throws PersistenceException
     *             wrapping a persistence implementation specific exception
     */
    public Problem getProblem(long id) throws PersistenceException {
        Connection conn = null;
        try {
            conn = Database.createConnection();
            PreparedStatement ps = null;
            try {
                ps = conn.prepareStatement(ProblemPersistenceImpl.GET_PROBLEM);
                ps.setLong(1, id);
                ResultSet rs = ps.executeQuery();
                if (!rs.next()) {
                    return null;
                }
                Problem problem = this.populateProblem(rs);
                long limitId = rs.getLong(DatabaseConstants.PROBLEM_LIMITS_ID);
                ps = conn.prepareStatement(ProblemPersistenceImpl.GET_LIMIT);
                ps.setLong(1, limitId);
                rs = ps.executeQuery();
                if (rs.next()) {
                    Limit limit = this.populateLimit(rs);
                    problem.setLimit(limit);
                }
                return problem;
            } finally {
                Database.dispose(ps);
            }
        } catch (SQLException e) {
            throw new PersistenceException("Failed to get the contest with id " + id, e);
        } finally {
            Database.dispose(conn);
        }
    }

    /**
     * Populates a Problem with given ResultSet.
     *
     * @param rs
     * @return an Problem instance
     * @throws SQLException
     */
    private Problem populateProblem(ResultSet rs) throws SQLException {
        Problem problem = new Problem();
        problem.setId(rs.getLong(DatabaseConstants.PROBLEM_PROBLEM_ID));
        problem.setTitle(rs.getString(DatabaseConstants.PROBLEM_TITLE));
        problem.setContestId(rs.getLong(DatabaseConstants.PROBLEM_CONTEST_ID));
        problem.setCode(rs.getString(DatabaseConstants.PROBLEM_CODE));
        problem.setAuthor(rs.getString(DatabaseConstants.PROBLEM_AUTHOR));
        problem.setSource(rs.getString(DatabaseConstants.PROBLEM_SOURCE));
        problem.setContest(rs.getString(DatabaseConstants.PROBLEM_CONTEST));
        problem.setChecker(rs.getBoolean(DatabaseConstants.PROBLEM_CHECKER));
        problem.setRevision(rs.getInt(DatabaseConstants.PROBLEM_REVISION));
        problem.setColor(rs.getString(DatabaseConstants.PROBLEM_COLOR));
        problem.setScore(rs.getInt(DatabaseConstants.PROBLEM_SCORE));
        return problem;
    }

    /**
     * Populates a Limit with given ResultSet.
     *
     * @param rs
     * @return an Limit instance
     * @throws SQLException
     */
    private Limit populateLimit(ResultSet rs) throws SQLException {
        Limit limit = new Limit();
        limit.setId(rs.getLong(DatabaseConstants.LIMITS_LIMITS_ID));
        limit.setTimeLimit(rs.getInt(DatabaseConstants.LIMITS_TIME_LIMIT));
        limit.setMemoryLimit(rs.getInt(DatabaseConstants.LIMITS_MEMORY_LIMIT));
        limit.setSubmissionLimit(rs.getInt(DatabaseConstants.LIMITS_SUBMISSION_LIMIT));
        limit.setOutputLimit(rs.getInt(DatabaseConstants.LIMITS_OUTPUT_LIMIT));
        return limit;
    }

    public List<Problem> searchProblems(ProblemCriteria criteria) throws PersistenceException {
        return this.searchProblems(criteria, 0, Integer.MAX_VALUE);
    }

    /**
     * <p>
     * Searches all problems according with the given criteria in persistence layer.
     * </p>
     *
     * @return a list of problems according with the given criteria
     * @param criteria
     *            the problem search criteria
     * @param offset
     *            the offset of the start position to search
     * @param count
     *            the maximum number of problems in returned list
     * @throws PersistenceException
     *             wrapping a persistence implementation specific exception
     */
    public List<Problem> searchProblems(ProblemCriteria criteria, int offset, int count) throws PersistenceException {
        Connection conn = null;
        try {
            conn = Database.createConnection();
            PreparedStatement ps = null;
            try {
                ps = conn.prepareStatement(this.buildSearchQuery(criteria, offset, count));
                ResultSet rs = ps.executeQuery();
                List<Problem> problems = new ArrayList<Problem>();
                while (rs.next()) {
                    Problem problem = this.populateProblem(rs);
                    Limit limit = this.populateLimit(rs);
                    problem.setLimit(limit);
                    problems.add(problem);
                }
                return problems;
            } finally {
                Database.dispose(ps);
            }
        } catch (SQLException e) {
            throw new PersistenceException("Failed to search the problems", e);
        } finally {
            Database.dispose(conn);
        }
    }

    public int getProblemsCount(long contestId) throws PersistenceException {
        Connection conn = null;
        try {
            conn = Database.createConnection();
            PreparedStatement ps = null;
            try {
                ps = conn.prepareStatement("select count(*) from problem where contest_id=? and active=1");
                ps.setLong(1, contestId);
                ResultSet rs = ps.executeQuery();

                if (rs.next()) {
                    return rs.getInt(1);
                } else {
                    return 0;
                }
            } finally {
                Database.dispose(ps);
            }
        } catch (SQLException e) {
            throw new PersistenceException("Failed to search the problems count", e);
        } finally {
            Database.dispose(conn);
        }
    }

    private String buildSearchQuery(ProblemCriteria criteria, int offset, int count) {
        StringBuffer sb = new StringBuffer();
        sb.append(ProblemPersistenceImpl.SEARCH_PROBLEMS);
        if (criteria.getContestId() != null) {
            sb.append(" AND " + DatabaseConstants.PROBLEM_CONTEST_ID + "=" + criteria.getContestId());
        }
        if (criteria.getCode() != null) {
            String problemCode = criteria.getCode().replaceAll("\\W", "");
            sb.append(" AND " + DatabaseConstants.PROBLEM_CODE + "='" + problemCode +"'");
        }
        sb.append(" ORDER BY " + DatabaseConstants.PROBLEM_CODE);
        sb.append(" LIMIT " + offset + "," + count);
        System.out.println(sb.toString());
        return sb.toString();
    }
}
TOP

Related Classes of cn.edu.zju.acm.onlinejudge.persistence.sql.ProblemPersistenceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.