org.pegadi.server.score.ScoreServerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.pegadi.server.score.ScoreServerImpl.java

Source

/**
 * Copyright 1999-2009 The Pegadi Team
 *
 * 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.
 */
/**
 * Server for recording scores.
 *
 * @author Hvard Wigtil <havardw at pvv.org>
 * @author Jan-Preben Mossin <jpmossin@underdusken.no>
 * @author Marvin B. Lillehaug <lillehau@underdusken.no>
 */
package org.pegadi.server.score;

import no.dusken.common.model.Person;
import org.pegadi.games.Score;
import org.pegadi.games.tetris.TetrisScore;
import org.pegadi.server.ScoreServer;
import org.pegadi.server.user.UserServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;

import javax.sql.DataSource;
import java.sql.*;
import java.util.*;
import java.util.Date;

public class ScoreServerImpl implements ScoreServer {

    /**
     * User server to look up user names.
     */
    protected UserServer userServer;

    private TetrisScoreRowMapper mapper;
    private JdbcTemplate template;

    private final Logger log = LoggerFactory.getLogger(getClass());

    public ScoreServerImpl() {
        mapper = new TetrisScoreRowMapper();
    }

    public void setDataSource(DataSource dataSource) {
        template = new JdbcTemplate(dataSource);
    }

    public void setUserServer(UserServer userServer) {
        this.userServer = userServer;
    }

    /**
     * Starts score recording for a new game. The <code>Score</code> object that is
     * returned <i>must</i> be used when calling {@link #updateScore } and
     * {@link #endGame }, as each score has an unique ID.
     *
     * @param domain The domain for the game.
     * @return A new Score object, with the score set to 0. If the domain is not known,
     *         this method will return <code>null</code>.
     */

    public Score startGame(final Person person, String domain) {

        if (domain.equals("tetris")) {
            final String insertSql = "insert into score_tetris (userID, score, level, linecount, starttime, active) values (?, ?, ?, ?, ?, true)";
            KeyHolder keyHolder = new GeneratedKeyHolder(); // The key/id of the new score is needed
            template.update(new PreparedStatementCreator() {
                public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
                    PreparedStatement statement = con.prepareStatement(insertSql, new String[] { "ID" });
                    statement.setString(1, person.getUsername());
                    statement.setLong(2, 0); // score
                    statement.setInt(3, 1); // level
                    statement.setInt(4, 0); // lines
                    statement.setTimestamp(5, new Timestamp((new GregorianCalendar()).getTimeInMillis()));

                    return statement;
                }
            }, keyHolder);

            int scoreId = keyHolder.getKey().intValue();

            return new TetrisScore(scoreId, person.getUsername(), person.getName(), 1);
        } else {
            log.error("Domain '{}' not implemented yet!", domain);
            return null;
        }

    }

    /**
     * Updates the score for a running game. The <code>Score</code> object must have the
     * same ID as the object returned by {@link #startGame}, and the client must set the
     * new value for score before updating.
     *
     * @param score The current score.
     */
    public void updateScore(Score score) {
        if (score instanceof TetrisScore) {
            TetrisScore tscore = (TetrisScore) score;
            template.update("Update score_tetris Set score=?, level=?, linecount=? Where ID=? And userID=?",
                    tscore.getScore(), tscore.getLevel(), tscore.getLines(), tscore.getID(), tscore.getUserID());
        } else {
            log.error("Update for Score not implemented yet!");
        }
    }

    /**
     * Records the final score for a game.The <code>Score</code> object must have the
     * same ID as the object returned by {@link #startGame}, and the client must set the
     * final value for the score.
     *
     * @param score The final score.
     * @return The same score object, with the <code>active</code> property set to false.
     * @see org.pegadi.games.Score#isActive
     */
    public Score endGame(Score score) {
        if (score instanceof TetrisScore) {
            TetrisScore tscore = (TetrisScore) score;
            template.update(
                    "update score_tetris set score=?, level=?, linecount=?, starttime=?, active=false where ID=? and userID=?",
                    tscore.getScore(), tscore.getLevel(), tscore.getLines(),
                    new Timestamp((new GregorianCalendar()).getTimeInMillis()), tscore.getID(), tscore.getUserID());

            Date date = new Date();
            long rank = getTetrisRank(tscore.getID());

            return new TetrisScore(tscore.getID(), tscore.getUserID(), tscore.getUserName(), rank,
                    tscore.getScore(), tscore.getLevel(), tscore.getLines(), date);
        }

        else {
            log.error("Update for Score not implemented yet!");
            return null;
        }

    }

    /**
     * Cancels a game in progress.
     *
     * @param score The game to cancel.
     */
    public void cancelGame(String userID, Score score) {
    }

    /**
     * Returns the <code>count</code> best scores ever.
     * Because user information is not in the same db as tetris scores
     * filtering for actives uses UserServer 
     *
     * @param count  Number of scores to return.
     * @param domain The game domain
     * @return List of scores.
     * @see org.pegadi.games.Score
     */
    public List<? extends Score> getHighScore(String domain, int count, boolean activesOnly) {
        if (domain.equals("tetris")) {
            if (activesOnly) {
                return getActiveTetrisHighScores(count);
            } else {
                return getTetrisHighScores(0, count);
            }
        } else {
            log.error("Domain not implemented yet!");
            return null;
        }
    }

    private List<TetrisScore> getTetrisHighScores(int start, int count) {
        String query = "select * from score_tetris where active=? order by score desc limit ?,?";

        return template.query(query, mapper, false, start, count);
    }

    // This method querys the db for more scores until activeScores.size = count
    private List<TetrisScore> getActiveTetrisHighScores(int count) {
        List<TetrisScore> activeScores = new ArrayList<TetrisScore>(count);
        List<TetrisScore> allScores;

        int start = 0;

        do {
            allScores = getTetrisHighScores(start, count);
            for (TetrisScore score : allScores) {
                String userId = score.getUserID();
                if (userServer.isActive(userId)) {
                    activeScores.add(score);
                }
            }

            start += count;

        } while (activeScores.size() < count);

        return activeScores;

    }

    /**
     * Returns the <code>count</code> best scores for the given user ID.
     *
     * @param userID user ID to return scores for.
     * @param count  Number of scores to return.
     * @param domain The game domain
     * @return List of scores.
     * @see org.pegadi.games.Score
     */
    public List<? extends Score> getUserScore(String domain, String userID, int count) {
        if (domain.equals("tetris")) {
            return template.query(
                    "select * from score_tetris where userID=? and active=false order by score Desc limit ?",
                    mapper, userID, count);
        } else {
            log.error("Domain not implemented yet!");
            return null;
        }
    }

    /**
     * Returns the <code>count</code> best scores the given date.
     *
     * @param day    The date to return scores from.
     * @param count  Number of scores to return.
     * @param domain The game domain
     * @return List of scores.
     * @see org.pegadi.games.Score
     */
    public List<? extends Score> getDayScore(String domain, Date day, int count) {
        if (domain.equals("tetris")) {
            Calendar cal = Calendar.getInstance();
            Date start, end;

            cal.setTime(day);
            cal.set(Calendar.HOUR_OF_DAY, 0);
            cal.set(Calendar.MINUTE, 0);
            cal.set(Calendar.SECOND, 0);
            start = cal.getTime();

            cal.set(Calendar.HOUR_OF_DAY, 23);
            cal.set(Calendar.MINUTE, 59);
            cal.set(Calendar.SECOND, 59);
            end = cal.getTime();

            Timestamp startstamp = new Timestamp(start.getTime());
            Timestamp endstamp = new Timestamp(end.getTime());

            return template.query(
                    "select * from score_tetris where starttime > ? and starttime < ?  order by score desc limit ?",
                    mapper, startstamp, endstamp, count);
        } else {
            log.error("Domain '{}' not implemented yet.", domain);
            return null;
        }
    }

    /**
     * Returns the score's rank in the database.
     * This is tyhe number of scores in the database that are better
     * than <code>score</code> + 1;
     */
    private long getTetrisRank(long score) {
        long rank = template.queryForLong("select count(*) from score_tetris where score > ?", score);
        return (++rank);
    }

    private class TetrisScoreRowMapper implements ParameterizedRowMapper<TetrisScore> {

        public TetrisScore mapRow(ResultSet rs, int i) throws SQLException {
            long score = rs.getLong("score");
            String username = rs.getString("userID");
            Person user = userServer.getUserByUsername(username);
            String name = user.getName();

            return new TetrisScore(rs.getLong("ID"), username, name, getTetrisRank(score), score,
                    rs.getInt("level"), rs.getInt("linecount"), rs.getTimestamp("starttime"));

        }
    }

}