Depot implementation of the stat system persistence - hopefully schema compatible with the old version. This one is a little more complicated and Whirled doesn't have any stats yet so I was a little at a loss at how to test all of it. Perhaps somebody at Bang could make sure nothing crashes and burns horribly when e.g. a new string code is assigned?
git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@383 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
@@ -0,0 +1,105 @@
|
|||||||
|
//
|
||||||
|
// $Id: PuzzleManagerDelegate.java 209 2007-02-24 00:37:33Z mdb $
|
||||||
|
//
|
||||||
|
// Vilya library - tools for developing networked games
|
||||||
|
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
|
||||||
|
// http://www.threerings.net/code/vilya/
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library 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
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.threerings.stats.server.persist;
|
||||||
|
|
||||||
|
import com.samskivert.jdbc.depot.Key;
|
||||||
|
import com.samskivert.jdbc.depot.PersistentRecord;
|
||||||
|
import com.samskivert.jdbc.depot.annotation.Column;
|
||||||
|
import com.samskivert.jdbc.depot.annotation.Entity;
|
||||||
|
import com.samskivert.jdbc.depot.annotation.Id;
|
||||||
|
import com.samskivert.jdbc.depot.expression.ColumnExp;
|
||||||
|
|
||||||
|
@Entity(name="STAT_RECORD")
|
||||||
|
public class StatRecord extends PersistentRecord
|
||||||
|
{
|
||||||
|
// AUTO-GENERATED: FIELDS START
|
||||||
|
/** The column identifier for the {@link #playerId} field. */
|
||||||
|
public static final String PLAYER_ID = "playerId";
|
||||||
|
|
||||||
|
/** The qualified column identifier for the {@link #playerId} field. */
|
||||||
|
public static final ColumnExp PLAYER_ID_C =
|
||||||
|
new ColumnExp(StatRecord.class, PLAYER_ID);
|
||||||
|
|
||||||
|
/** The column identifier for the {@link #statCode} field. */
|
||||||
|
public static final String STAT_CODE = "statCode";
|
||||||
|
|
||||||
|
/** The qualified column identifier for the {@link #statCode} field. */
|
||||||
|
public static final ColumnExp STAT_CODE_C =
|
||||||
|
new ColumnExp(StatRecord.class, STAT_CODE);
|
||||||
|
|
||||||
|
/** The column identifier for the {@link #statData} field. */
|
||||||
|
public static final String STAT_DATA = "statData";
|
||||||
|
|
||||||
|
/** The qualified column identifier for the {@link #statData} field. */
|
||||||
|
public static final ColumnExp STAT_DATA_C =
|
||||||
|
new ColumnExp(StatRecord.class, STAT_DATA);
|
||||||
|
// AUTO-GENERATED: FIELDS END
|
||||||
|
|
||||||
|
public static final int SCHEMA_VERSION = 2;
|
||||||
|
|
||||||
|
/** The identifier of the player this is a stat for. */
|
||||||
|
@Id
|
||||||
|
@Column(name="PLAYER_ID")
|
||||||
|
public int playerId;
|
||||||
|
|
||||||
|
/** The code of the stat. */
|
||||||
|
@Id
|
||||||
|
@Column(name="STAT_CODE")
|
||||||
|
public int statCode;
|
||||||
|
|
||||||
|
/** The data associated with the stat. */
|
||||||
|
@Column(name="STAT_DATA")
|
||||||
|
public byte[] statData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An empty constructor for unmarshalling.
|
||||||
|
*/
|
||||||
|
public StatRecord ()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A constructor that populates all our fields.
|
||||||
|
*/
|
||||||
|
public StatRecord (int playerId, int statCode, byte[] data)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.playerId = playerId;
|
||||||
|
this.statCode = statCode;
|
||||||
|
this.statData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AUTO-GENERATED: METHODS START
|
||||||
|
/**
|
||||||
|
* Create and return a primary {@link Key} to identify a {@link #StatRecord}
|
||||||
|
* with the supplied key values.
|
||||||
|
*/
|
||||||
|
public static Key<StatRecord> getKey (int playerId, int statCode)
|
||||||
|
{
|
||||||
|
return new Key<StatRecord>(
|
||||||
|
StatRecord.class,
|
||||||
|
new String[] { PLAYER_ID, STAT_CODE },
|
||||||
|
new Comparable[] { playerId, statCode });
|
||||||
|
}
|
||||||
|
// AUTO-GENERATED: METHODS END
|
||||||
|
}
|
||||||
@@ -5,28 +5,34 @@ package com.threerings.stats.server.persist;
|
|||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.Date;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.sql.Timestamp;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import com.samskivert.io.ByteArrayOutInputStream;
|
import com.samskivert.io.ByteArrayOutInputStream;
|
||||||
import com.samskivert.io.PersistenceException;
|
import com.samskivert.io.PersistenceException;
|
||||||
import com.samskivert.jdbc.ConnectionProvider;
|
import com.samskivert.jdbc.ConnectionProvider;
|
||||||
import com.samskivert.jdbc.DatabaseLiaison;
|
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
import com.samskivert.jdbc.JDBCUtil;
|
||||||
import com.samskivert.jdbc.SimpleRepository;
|
import com.samskivert.jdbc.depot.CacheInvalidator;
|
||||||
|
import com.samskivert.jdbc.depot.DepotRepository;
|
||||||
|
import com.samskivert.jdbc.depot.PersistenceContext;
|
||||||
|
import com.samskivert.jdbc.depot.PersistentRecord;
|
||||||
|
import com.samskivert.jdbc.depot.PersistenceContext.CacheEvictionFilter;
|
||||||
|
import com.samskivert.jdbc.depot.annotation.Computed;
|
||||||
|
import com.samskivert.jdbc.depot.annotation.Entity;
|
||||||
|
import com.samskivert.jdbc.depot.clause.FieldOverride;
|
||||||
|
import com.samskivert.jdbc.depot.clause.FromOverride;
|
||||||
|
import com.samskivert.jdbc.depot.clause.QueryClause;
|
||||||
|
import com.samskivert.jdbc.depot.clause.Where;
|
||||||
|
import com.samskivert.jdbc.depot.expression.FunctionExp;
|
||||||
import com.samskivert.util.HashIntMap;
|
import com.samskivert.util.HashIntMap;
|
||||||
import com.samskivert.util.StringUtil;
|
|
||||||
|
|
||||||
import com.threerings.io.ObjectInputStream;
|
import com.threerings.io.ObjectInputStream;
|
||||||
import com.threerings.io.ObjectOutputStream;
|
import com.threerings.io.ObjectOutputStream;
|
||||||
@@ -38,7 +44,7 @@ import static com.threerings.stats.Log.log;
|
|||||||
/**
|
/**
|
||||||
* Responsible for the persistent storage of per-player statistics.
|
* Responsible for the persistent storage of per-player statistics.
|
||||||
*/
|
*/
|
||||||
public class StatRepository extends SimpleRepository
|
public class StatRepository extends DepotRepository
|
||||||
implements Stat.AuxDataSource
|
implements Stat.AuxDataSource
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -56,7 +62,16 @@ public class StatRepository extends SimpleRepository
|
|||||||
public StatRepository (ConnectionProvider conprov)
|
public StatRepository (ConnectionProvider conprov)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
super(conprov, STAT_DB_IDENT);
|
this(new PersistenceContext(STAT_DB_IDENT, conprov));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new statistics repository with the specified persistence context.
|
||||||
|
*/
|
||||||
|
public StatRepository (PersistenceContext context)
|
||||||
|
throws PersistenceException
|
||||||
|
{
|
||||||
|
super(context);
|
||||||
|
|
||||||
// load up our string set mappings
|
// load up our string set mappings
|
||||||
loadStringCodes(null);
|
loadStringCodes(null);
|
||||||
@@ -65,41 +80,36 @@ public class StatRepository extends SimpleRepository
|
|||||||
/**
|
/**
|
||||||
* Loads the stats associated with the specified player.
|
* Loads the stats associated with the specified player.
|
||||||
*/
|
*/
|
||||||
public ArrayList<Stat> loadStats (final int playerId)
|
public ArrayList<Stat> loadStats (int playerId)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
final ArrayList<Stat> stats = new ArrayList<Stat>();
|
ArrayList<Stat> stats = new ArrayList<Stat>();
|
||||||
final String query = "select STAT_CODE, STAT_DATA from STATS where PLAYER_ID = " + playerId;
|
Where where = new Where(StatRecord.PLAYER_ID_C, playerId);
|
||||||
execute(new Operation<Object>() {
|
for (StatRecord record : findAll(StatRecord.class, where)) {
|
||||||
public Object invoke (Connection conn, DatabaseLiaison liaison)
|
Stat stat = decodeStat(record.statCode, record.statData);
|
||||||
throws SQLException, PersistenceException
|
if (stat != null) {
|
||||||
{
|
stats.add(stat);
|
||||||
Statement stmt = conn.createStatement();
|
|
||||||
try {
|
|
||||||
ResultSet rs = stmt.executeQuery(query);
|
|
||||||
while (rs.next()) {
|
|
||||||
Stat stat = decodeStat(
|
|
||||||
rs.getInt(1), (byte[])rs.getObject(2));
|
|
||||||
if (stat != null) {
|
|
||||||
stats.add(stat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes all stats associated with the specified player.
|
* Deletes all stats associated with the specified player.
|
||||||
*/
|
*/
|
||||||
public void deleteStats (int playerId)
|
public void deleteStats (final int playerId)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
update("delete from STATS where PLAYER_ID = " + playerId);
|
CacheInvalidator invalidator = new CacheInvalidator() {
|
||||||
|
public void invalidate (PersistenceContext ctx) {
|
||||||
|
ctx.cacheTraverse(StatRecord.class.getName(), new CacheEvictionFilter<StatRecord>() {
|
||||||
|
public boolean testForEviction (Serializable key, StatRecord record) {
|
||||||
|
return record != null && record.playerId == playerId;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
deleteAll(StatRecord.class, new Where(StatRecord.PLAYER_ID_C, playerId), invalidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -222,11 +232,7 @@ public class StatRepository extends SimpleRepository
|
|||||||
protected void updateStat (int playerId, final Stat stat)
|
protected void updateStat (int playerId, final Stat stat)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
final String uquery = "update STATS set STAT_DATA = ?" +
|
ByteArrayOutInputStream out = new ByteArrayOutInputStream();
|
||||||
" where PLAYER_ID = " + playerId + " and STAT_CODE = " + stat.getCode();
|
|
||||||
final String iquery = "insert into STATS (PLAYER_ID, STAT_CODE, " +
|
|
||||||
"STAT_DATA) values (" + playerId + ", " + stat.getCode() + ", ?)";
|
|
||||||
final ByteArrayOutInputStream out = new ByteArrayOutInputStream();
|
|
||||||
try {
|
try {
|
||||||
stat.persistTo(new ObjectOutputStream(out), this);
|
stat.persistTo(new ObjectOutputStream(out), this);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
@@ -234,111 +240,71 @@ public class StatRepository extends SimpleRepository
|
|||||||
throw new PersistenceException(errmsg, ioe);
|
throw new PersistenceException(errmsg, ioe);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now update (or insert) the flattened data into the database
|
store(new StatRecord(playerId, stat.getCode(), out.toByteArray()));
|
||||||
executeUpdate(new Operation<Object>() {
|
|
||||||
public Object invoke (Connection conn, DatabaseLiaison liaison)
|
|
||||||
throws SQLException, PersistenceException
|
|
||||||
{
|
|
||||||
PreparedStatement stmt = conn.prepareStatement(uquery);
|
|
||||||
try {
|
|
||||||
stmt.setBinaryStream(1, out.getInputStream(), out.size());
|
|
||||||
if (stmt.executeUpdate() == 0) {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
stmt = conn.prepareStatement(iquery);
|
|
||||||
stmt.setBinaryStream(1, out.getInputStream(), out.size());
|
|
||||||
JDBCUtil.checkedUpdate(stmt, 1);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Computed @Entity
|
||||||
|
protected static class MaxStatCodeRecord extends PersistentRecord {
|
||||||
|
int maxCode;
|
||||||
|
};
|
||||||
|
|
||||||
/** Helper function for {@link #getStringCode}. */
|
/** Helper function for {@link #getStringCode}. */
|
||||||
protected Integer assignStringCode (final Stat.Type type, final String value)
|
protected Integer assignStringCode (final Stat.Type type, final String value)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
return executeUpdate(new Operation<Integer>() {
|
for (int ii = 0; ii < 10; ii++) {
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
MaxStatCodeRecord maxRecord = load(
|
||||||
throws SQLException, PersistenceException
|
MaxStatCodeRecord.class,
|
||||||
{
|
new FromOverride(StringCodeRecord.class),
|
||||||
for (int ii = 0; ii < 10; ii++) {
|
new FieldOverride("maxCode", new FunctionExp("MAX", StringCodeRecord.CODE_C)),
|
||||||
try {
|
new Where(StringCodeRecord.STAT_CODE_C, type.code()));
|
||||||
int code = getNextCode(conn, type);
|
|
||||||
// DEBUG: uncomment this to test code collision
|
|
||||||
// if (ii == 0 && code > 0) {
|
|
||||||
// code = code-1;
|
|
||||||
// }
|
|
||||||
insertStringCode(conn, type, value, code);
|
|
||||||
return code;
|
|
||||||
|
|
||||||
} catch (SQLException sqe) {
|
int code = maxRecord != null ? maxRecord.maxCode + 1 : 1;
|
||||||
// if this is not a duplicate row exception, something is booched and we
|
|
||||||
// just fail
|
|
||||||
if (!liaison.isDuplicateRowException(sqe)) {
|
|
||||||
throw sqe;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if it is a duplicate row exception, possibly someone inserted our value
|
// DEBUG: uncomment this to test code collision
|
||||||
// before we could, in which case we can just look up the new mapping
|
// if (ii == 0 && code > 0) {
|
||||||
int code = getCurrentCode(conn, type, value);
|
// code = code-1;
|
||||||
if (code != -1) {
|
// }
|
||||||
log.info("Value collision assigning string code [type=" + type +
|
|
||||||
", value=" + value + "].");
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise someone used the code we were trying to use and we just need
|
try {
|
||||||
// to loop around and get the next highest code
|
insert(new StringCodeRecord(type.code(), value, code));
|
||||||
log.info("Code collision assigning string code [type=" + type +
|
return code;
|
||||||
", value=" + value + "].");
|
|
||||||
}
|
} catch (PersistenceException pe) {
|
||||||
|
// if this is not a duplicate row exception, something is booched and we
|
||||||
|
// just fail
|
||||||
|
|
||||||
|
// if (!liaison.isDuplicateRowException(sqe)) {
|
||||||
|
// throw sqe;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if it is a duplicate row exception, possibly someone inserted our value
|
||||||
|
// before we could, in which case we can just look up the new mapping
|
||||||
|
StringCodeRecord record = load(
|
||||||
|
StringCodeRecord.class,
|
||||||
|
new Where(StringCodeRecord.STAT_CODE_C, type.code(),
|
||||||
|
StringCodeRecord.VALUE_C, value));
|
||||||
|
if (record != null) {
|
||||||
|
log.info("Value collision assigning string code [type=" + type +
|
||||||
|
", value=" + value + "].");
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
throw new SQLException("Unable to assign code after 10 attempts " +
|
|
||||||
"[type=" + type + ", value=" + value + "]");
|
// otherwise someone used the code we were trying to use and we just need
|
||||||
|
// to loop around and get the next highest code
|
||||||
|
log.info("Code collision assigning string code [type=" + type +
|
||||||
|
", value=" + value + "].");
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Helper function for {@link #assignStringCode}. */
|
|
||||||
protected int getNextCode (Connection conn, Stat.Type type)
|
|
||||||
throws SQLException
|
|
||||||
{
|
|
||||||
return getCode(conn, "select MAX(CODE)+1 from STRING_CODES where STAT_CODE = " +
|
|
||||||
type.code());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Helper function for {@link #assignStringCode}. */
|
|
||||||
protected int getCurrentCode (Connection conn, Stat.Type type, String value)
|
|
||||||
throws SQLException
|
|
||||||
{
|
|
||||||
return getCode(conn, "select CODE from STRING_CODES where STAT_CODE = " + type.code() +
|
|
||||||
" and VALUE = " + JDBCUtil.escape(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Helper function for {@link #getNextCode} and {@link #getCurrentCode}. */
|
|
||||||
protected int getCode (Connection conn, String query)
|
|
||||||
throws SQLException
|
|
||||||
{
|
|
||||||
int code = -1;
|
|
||||||
Statement stmt = conn.createStatement();
|
|
||||||
try {
|
|
||||||
ResultSet rs = stmt.executeQuery(query);
|
|
||||||
while (rs.next()) {
|
|
||||||
code = rs.getInt(1);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
}
|
||||||
return code;
|
throw new PersistenceException(
|
||||||
|
"Unable to assign code after 10 attempts [type=" + type + ", value=" + value + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper function for {@link #assignStringCode}. */
|
/** Helper function for {@link #assignStringCode}. */
|
||||||
protected void insertStringCode (Connection conn, Stat.Type type, String value, int code)
|
protected void insertStringCode (Connection conn, Stat.Type type, String value, int code)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
|
|
||||||
String query = "insert into STRING_CODES (STAT_CODE, VALUE, CODE) values(" + type.code() +
|
String query = "insert into STRING_CODES (STAT_CODE, VALUE, CODE) values(" + type.code() +
|
||||||
", " + JDBCUtil.escape(value) + ", " + code + ")";
|
", " + JDBCUtil.escape(value) + ", " + code + ")";
|
||||||
Statement stmt = conn.createStatement();
|
Statement stmt = conn.createStatement();
|
||||||
@@ -358,24 +324,16 @@ public class StatRepository extends SimpleRepository
|
|||||||
protected void loadStringCodes (Stat.Type type)
|
protected void loadStringCodes (Stat.Type type)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
final String query = "select STAT_CODE, VALUE, CODE from STRING_CODES " +
|
QueryClause[] clauses;
|
||||||
((type == null) ? "" : (" where STAT_CODE = " + type.code()));
|
if (type != null) {
|
||||||
execute(new Operation<Object>() {
|
clauses = new QueryClause[] { new Where(StringCodeRecord.STAT_CODE_C, type.code()) };
|
||||||
public Object invoke (Connection conn, DatabaseLiaison liaison)
|
} else {
|
||||||
throws SQLException, PersistenceException
|
clauses = new QueryClause[0];
|
||||||
{
|
}
|
||||||
Statement stmt = conn.createStatement();
|
|
||||||
try {
|
for (StringCodeRecord record : findAll(StringCodeRecord.class, clauses)) {
|
||||||
ResultSet rs = stmt.executeQuery(query);
|
mapStringCode(Stat.getType(record.statCode), record.value, record.code);
|
||||||
while (rs.next()) {
|
}
|
||||||
mapStringCode(Stat.getType(rs.getInt(1)), rs.getString(2), rs.getInt(3));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper function used at repository startup. */
|
/** Helper function used at repository startup. */
|
||||||
@@ -393,25 +351,11 @@ public class StatRepository extends SimpleRepository
|
|||||||
rmap.put(code, value);
|
rmap.put(code, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override // documentation inherited
|
@Override // from DepotRepository
|
||||||
protected void migrateSchema (Connection conn, DatabaseLiaison liaison)
|
protected void getManagedRecords (Set<Class<? extends PersistentRecord>> classes)
|
||||||
throws SQLException, PersistenceException
|
|
||||||
{
|
{
|
||||||
JDBCUtil.createTableIfMissing(conn, "STATS", new String[] {
|
classes.add(StatRecord.class);
|
||||||
"PLAYER_ID INTEGER NOT NULL",
|
classes.add(StringCodeRecord.class);
|
||||||
"STAT_CODE INTEGER NOT NULL",
|
|
||||||
"STAT_DATA BLOB NOT NULL",
|
|
||||||
"KEY (PLAYER_ID)",
|
|
||||||
"KEY (STAT_CODE)",
|
|
||||||
}, "");
|
|
||||||
|
|
||||||
JDBCUtil.createTableIfMissing(conn, "STRING_CODES", new String[] {
|
|
||||||
"STAT_CODE INTEGER NOT NULL",
|
|
||||||
"VALUE VARCHAR(255) NOT NULL",
|
|
||||||
"CODE INTEGER NOT NULL",
|
|
||||||
"UNIQUE (STAT_CODE, VALUE)",
|
|
||||||
"UNIQUE (STAT_CODE, CODE)",
|
|
||||||
}, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HashMap<Stat.Type,HashMap<String,Integer>> _stringToCode =
|
protected HashMap<Stat.Type,HashMap<String,Integer>> _stringToCode =
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
//
|
||||||
|
// $Id: PuzzleManagerDelegate.java 209 2007-02-24 00:37:33Z mdb $
|
||||||
|
//
|
||||||
|
// Vilya library - tools for developing networked games
|
||||||
|
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
|
||||||
|
// http://www.threerings.net/code/vilya/
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library 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
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.threerings.stats.server.persist;
|
||||||
|
|
||||||
|
import com.samskivert.jdbc.depot.Key;
|
||||||
|
import com.samskivert.jdbc.depot.PersistentRecord;
|
||||||
|
import com.samskivert.jdbc.depot.annotation.Column;
|
||||||
|
import com.samskivert.jdbc.depot.annotation.Entity;
|
||||||
|
import com.samskivert.jdbc.depot.annotation.Id;
|
||||||
|
import com.samskivert.jdbc.depot.annotation.Table;
|
||||||
|
import com.samskivert.jdbc.depot.annotation.UniqueConstraint;
|
||||||
|
import com.samskivert.jdbc.depot.expression.ColumnExp;
|
||||||
|
|
||||||
|
@Entity(name="STRING_CODES")
|
||||||
|
@Table(uniqueConstraints={
|
||||||
|
@UniqueConstraint(columnNames={StringCodeRecord.STAT_CODE, StringCodeRecord.VALUE}),
|
||||||
|
@UniqueConstraint(columnNames={StringCodeRecord.STAT_CODE, StringCodeRecord.CODE})})
|
||||||
|
public class StringCodeRecord extends PersistentRecord
|
||||||
|
{
|
||||||
|
// AUTO-GENERATED: FIELDS START
|
||||||
|
/** The column identifier for the {@link #statCode} field. */
|
||||||
|
public static final String STAT_CODE = "statCode";
|
||||||
|
|
||||||
|
/** The qualified column identifier for the {@link #statCode} field. */
|
||||||
|
public static final ColumnExp STAT_CODE_C =
|
||||||
|
new ColumnExp(StringCodeRecord.class, STAT_CODE);
|
||||||
|
|
||||||
|
/** The column identifier for the {@link #value} field. */
|
||||||
|
public static final String VALUE = "value";
|
||||||
|
|
||||||
|
/** The qualified column identifier for the {@link #value} field. */
|
||||||
|
public static final ColumnExp VALUE_C =
|
||||||
|
new ColumnExp(StringCodeRecord.class, VALUE);
|
||||||
|
|
||||||
|
/** The column identifier for the {@link #code} field. */
|
||||||
|
public static final String CODE = "code";
|
||||||
|
|
||||||
|
/** The qualified column identifier for the {@link #code} field. */
|
||||||
|
public static final ColumnExp CODE_C =
|
||||||
|
new ColumnExp(StringCodeRecord.class, CODE);
|
||||||
|
// AUTO-GENERATED: FIELDS END
|
||||||
|
|
||||||
|
public static final int SCHEMA_VERSION = 2;
|
||||||
|
|
||||||
|
/** The code of the stat. */
|
||||||
|
@Id
|
||||||
|
@Column(name="STAT_CODE")
|
||||||
|
public int statCode;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name="VALUE")
|
||||||
|
public String value;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name="CODE")
|
||||||
|
public int code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An empty constructor for unmarshalling.
|
||||||
|
*/
|
||||||
|
public StringCodeRecord ()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A constructor that populates all our fields.
|
||||||
|
*/
|
||||||
|
public StringCodeRecord (int statCode, String value, int code)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.statCode = statCode;
|
||||||
|
this.value = value;
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AUTO-GENERATED: METHODS START
|
||||||
|
/**
|
||||||
|
* Create and return a primary {@link Key} to identify a {@link #StringCodeRecord}
|
||||||
|
* with the supplied key values.
|
||||||
|
*/
|
||||||
|
public static Key<StringCodeRecord> getKey (int statCode, String value, int code)
|
||||||
|
{
|
||||||
|
return new Key<StringCodeRecord>(
|
||||||
|
StringCodeRecord.class,
|
||||||
|
new String[] { STAT_CODE, VALUE, CODE },
|
||||||
|
new Comparable[] { statCode, value, code });
|
||||||
|
}
|
||||||
|
// AUTO-GENERATED: METHODS END
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user