Empire resources in XML dumps

* Added dump view for empire resources

* Added empire resource information storage class and associated row
mapper

* Integrated empire resource information into the summary generator
This commit is contained in:
Emmanuel BENOîT 2012-01-19 09:35:12 +01:00
parent ce6d86d344
commit 9b346a80c2
9 changed files with 542 additions and 15 deletions

View file

@ -0,0 +1,46 @@
package com.deepclone.lw.beans.bt.es;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
import com.deepclone.lw.beans.bt.es.data.EmpireResourceInformation;
/**
* Empire resource row mapper
*
* <p>
* This class is responsible for transforming rows from <code>bugs.dump_emp_resources_view</code>
* into {@link EmpireResourceInformation} instances.
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
final class EmpireResourceInformationMapper
implements RowMapper< EmpireResourceInformation >
{
/**
* Map a row from <code>bugs.dump_emp_resources_view</code>
*
* <p>
* Create a new {@link EmpireResourceInformation} instance and set its fields using the row's
* contents.
*/
@Override
public EmpireResourceInformation mapRow( ResultSet rs , int rowNum )
throws SQLException
{
EmpireResourceInformation empRes = new EmpireResourceInformation( );
empRes.setResource( rs.getString( "resource_name" ) );
empRes.setOwed( rs.getDouble( "empres_owed" ) );
empRes.setPossessed( rs.getDouble( "empres_possessed" ) );
return empRes;
}
}

View file

@ -2,6 +2,7 @@ package com.deepclone.lw.beans.bt.es;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.sql.DataSource; import javax.sql.DataSource;
@ -14,6 +15,7 @@ import com.deepclone.lw.beans.bt.es.data.AllianceInformation;
import com.deepclone.lw.beans.bt.es.data.BuildingsInformation; import com.deepclone.lw.beans.bt.es.data.BuildingsInformation;
import com.deepclone.lw.beans.bt.es.data.DebugInformation; import com.deepclone.lw.beans.bt.es.data.DebugInformation;
import com.deepclone.lw.beans.bt.es.data.EmpireInformation; import com.deepclone.lw.beans.bt.es.data.EmpireInformation;
import com.deepclone.lw.beans.bt.es.data.EmpireResourceInformation;
import com.deepclone.lw.beans.bt.es.data.FleetInformation; import com.deepclone.lw.beans.bt.es.data.FleetInformation;
import com.deepclone.lw.beans.bt.es.data.MovementInformation; import com.deepclone.lw.beans.bt.es.data.MovementInformation;
import com.deepclone.lw.beans.bt.es.data.PlanetInformation; import com.deepclone.lw.beans.bt.es.data.PlanetInformation;
@ -51,6 +53,9 @@ public class EmpireSummaryBean
/** SQL query that accesses the main empire dump view */ /** SQL query that accesses the main empire dump view */
private static final String Q_EMPIRE = SQL_START + "main" + SQL_END; private static final String Q_EMPIRE = SQL_START + "main" + SQL_END;
/** SQL query that accesses the resources dump view */
private static final String Q_RESOURCES = SQL_START + "emp_resources" + SQL_END;
/** SQL query that accesses the research dump view */ /** SQL query that accesses the research dump view */
private static final String Q_RESEARCH = SQL_START + "research" + SQL_END; private static final String Q_RESEARCH = SQL_START + "research" + SQL_END;
@ -81,6 +86,9 @@ public class EmpireSummaryBean
/** Top-level row mapper */ /** Top-level row mapper */
private final DebugInformationMapper mMainInfo; private final DebugInformationMapper mMainInfo;
/** Empire resources row mapper */
private final EmpireResourceInformationMapper mResources;
/** Empire research row mapper */ /** Empire research row mapper */
private final ResearchInformationMapper mResearch; private final ResearchInformationMapper mResearch;
@ -119,6 +127,7 @@ public class EmpireSummaryBean
} ); } );
this.mMainInfo = new DebugInformationMapper( ); this.mMainInfo = new DebugInformationMapper( );
this.mResources = new EmpireResourceInformationMapper( );
this.mResearch = new ResearchInformationMapper( ); this.mResearch = new ResearchInformationMapper( );
this.mPlanet = new PlanetInformationMapper( ); this.mPlanet = new PlanetInformationMapper( );
this.mPlanetResources = new ResourceRowMapper( ); this.mPlanetResources = new ResourceRowMapper( );
@ -154,6 +163,7 @@ public class EmpireSummaryBean
public String getSummary( int empireId ) public String getSummary( int empireId )
{ {
DebugInformation empireDump = this.dTemplate.queryForObject( Q_EMPIRE , this.mMainInfo , empireId ); DebugInformation empireDump = this.dTemplate.queryForObject( Q_EMPIRE , this.mMainInfo , empireId );
this.getResources( empireId , empireDump );
this.getResearch( empireId , empireDump ); this.getResearch( empireId , empireDump );
this.getPlanets( empireId , empireDump ); this.getPlanets( empireId , empireDump );
@ -163,6 +173,27 @@ public class EmpireSummaryBean
} }
/**
* Extract resources information
*
* <p>
* Read the list of empire resources from the appropriate view and add the extracted entries to
* the empire's list of resources.
*
* @param empireId
* the empire's identifier
* @param empireDump
* the top-level instance
*/
private void getResources( int empireId , DebugInformation empireDump )
{
List< EmpireResourceInformation > resources = empireDump.getEmpire( ).getResources( );
for ( EmpireResourceInformation empRes : this.dTemplate.query( Q_RESOURCES , this.mResources , empireId ) ) {
resources.add( empRes );
}
}
/** /**
* Get research information * Get research information
* *

View file

@ -2,79 +2,140 @@ package com.deepclone.lw.beans.bt.es.data;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute; import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
@XStreamAlias( "empire" ) /**
* Empire information record for XML dumps
*
* <p>
* This class regroups all "main" empire information in XML dumps. This includes the empire's name
* and identifier, details about the alliance, and the list of resources.
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
@SuppressWarnings( "serial" )
public class EmpireInformation public class EmpireInformation
implements Serializable implements Serializable
{ {
private static final long serialVersionUID = 1L; /** The empire's numeric identifier */
@XStreamAsAttribute @XStreamAsAttribute
@XStreamAlias( "id" ) private Integer id;
private int id;
/** The empire's name */
@XStreamAsAttribute @XStreamAsAttribute
@XStreamAlias( "name" )
private String name; private String name;
/** The empire's cash */
@XStreamAsAttribute @XStreamAsAttribute
@XStreamAlias( "cash" ) private Double cash;
private double cash;
/**
* The alliance the empire belongs to or has requested membership of (or <code>null</code> if
* the empire is neither in an alliance nor requesting to join one)
*/
private AllianceInformation alliance; private AllianceInformation alliance;
/** The empire's resources */
private final ArrayList< EmpireResourceInformation > resources = new ArrayList< EmpireResourceInformation >( );
public int getId( )
/** @return the empire's numeric identifier */
public Integer getId( )
{ {
return id; return this.id;
} }
/**
* Set the empire's numeric identifier
*
* @param id
* the empire's numeric identifier
*/
public void setId( int id ) public void setId( int id )
{ {
this.id = id; this.id = id;
} }
/** @return the empire's name */
public String getName( ) public String getName( )
{ {
return name; return this.name;
} }
/**
* Set the empire's name
*
* @param name
* the empire's name
*/
public void setName( String name ) public void setName( String name )
{ {
this.name = name; this.name = name;
} }
public double getCash( ) /** @return the amount of cash possessed by the empire */
public Double getCash( )
{ {
return cash; return this.cash;
} }
/**
* Set the amount of cash possessed by the empire
*
* @param cash
* the amount of cash possessed by the empire
*/
public void setCash( double cash ) public void setCash( double cash )
{ {
this.cash = cash; this.cash = cash;
} }
/**
* @return the alliance the empire belongs to or has requested membership of, or
* <code>null</code> if the empire is neither in an alliance nor requesting to join one
*/
public AllianceInformation getAlliance( ) public AllianceInformation getAlliance( )
{ {
return alliance; return this.alliance;
} }
/**
* Set the information about the alliance
*
* @param alliance
* the information about the alliance
*/
public void setAlliance( AllianceInformation alliance ) public void setAlliance( AllianceInformation alliance )
{ {
this.alliance = alliance; this.alliance = alliance;
} }
/**
* Access the list of resources
*
* @return the list of resources, even if none was set in the file the instance was loaded from.
*/
public List< EmpireResourceInformation > getResources( )
{
if ( this.resources == null ) {
return Collections.emptyList( );
}
return this.resources;
}
} }

View file

@ -0,0 +1,103 @@
package com.deepclone.lw.beans.bt.es.data;
import java.io.Serializable;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
/**
* Empire resources XML dump record
*
* <p>
* This class is used to store information about an empire's resources in debugging XML dumps. Each
* instance indicates the amount possessed or owed for a given type of resources.
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
@XStreamAlias( "resource" )
@SuppressWarnings( "serial" )
public class EmpireResourceInformation
implements Serializable
{
/** The type of resources */
@XStreamAlias( "id" )
@XStreamAsAttribute
private String resource;
/** The amount of resources possessed */
@XStreamAsAttribute
private Double possessed;
/** The amount of resources owed */
@XStreamAsAttribute
private Double owed;
/** @return the type of resources */
public String getResource( )
{
return this.resource;
}
/**
* Set the type of resources
*
* @param resource
* the type of resources
*
* @throws InvalidDumpContentsException
* if the specified resource type is <code>null</code>
*/
public void setResource( String resource )
throws InvalidDumpContentsException
{
if ( resource == null ) {
throw new InvalidDumpContentsException( this.getClass( ) , "resource" );
}
this.resource = resource;
}
/** @return the amount of resources possessed */
public Double getPossessed( )
{
return this.possessed;
}
/**
* Set the amount of resources possessed
*
* @param possessed
* the amount of resources possessed
*/
public void setPossessed( Double possessed )
{
this.possessed = possessed;
}
/** @return the amount of resources owed */
public Double getOwed( )
{
return this.owed;
}
/**
* Set the amount of resources owed
*
* @param owed
* the amount of resources owed
*/
public void setOwed( Double owed )
{
this.owed = owed;
}
}

View file

@ -1205,6 +1205,30 @@ CREATE VIEW bugs.dump_research_view
GRANT SELECT ON bugs.dump_research_view TO :dbuser; GRANT SELECT ON bugs.dump_research_view TO :dbuser;
/*
* Empire resources view
* ----------------------
*
* This view contains the details about empires' resources as they are needed
* by the XML dump generator.
*
* Columns:
* empire_id Identifier of the empire
* resource_name Text-based identifier of the resource type
* empres_possessed Amount of resources possessed by the empire
* empres_owed Amount of resources owed by the empire
*/
DROP VIEW IF EXISTS bugs.dump_emp_resources_view CASCADE;
CREATE VIEW bugs.dump_emp_resources_view
AS SELECT empire_id , name AS resource_name , empres_possessed , empres_owed
FROM emp.resources
INNER JOIN defs.strings ON id = resource_name_id;
GRANT SELECT
ON bugs.dump_emp_resources_view
TO :dbuser;
CREATE VIEW bugs.dump_planets_view CREATE VIEW bugs.dump_planets_view
AS SELECT ep.empire_id , ep.planet_id , p.population , AS SELECT ep.empire_id , ep.planet_id , p.population ,
( ph.current / p.population )::REAL AS current_happiness , ph.target AS target_happiness , ( ph.current / p.population )::REAL AS current_happiness , ph.target AS target_happiness ,
@ -1248,6 +1272,7 @@ GRANT SELECT ON bugs.dump_planets_view TO :dbuser;
* if there is no resource provider of that * if there is no resource provider of that
* type on the planet * type on the planet
*/ */
DROP VIEW IF EXISTS bugs.dump_planet_resources_view CASCADE;
CREATE VIEW bugs.dump_planet_resources_view CREATE VIEW bugs.dump_planet_resources_view
AS SELECT empire_id , planet_id , AS SELECT empire_id , planet_id ,
name AS resource_name , name AS resource_name ,

View file

@ -0,0 +1,36 @@
/*
* Tests for bugs.dump_emp_resources_view
*/
BEGIN;
/*
* We need a resource type, an empire and the associated resource record.
*/
\i utils/strings.sql
\i utils/resources.sql
\i utils/accounts.sql
\i utils/naming.sql
\i utils/universe.sql
SELECT _create_resources( 1 , 'resource' );
SELECT _create_emp_names( 1 , 'empire' );
INSERT INTO emp.empires( name_id , cash )
VALUES ( _get_emp_name( 'empire1' ) , 0 );
INSERT INTO emp.resources(
empire_id , resource_name_id , empres_possessed , empres_owed
) VALUES (
_get_emp_name( 'empire1' ) , _get_string( 'resource1' ) , 1 , 2
);
/***** TESTS BEGIN HERE *****/
SELECT plan( 1 );
SELECT diag_test_name( 'bugs.dump_emp_resources_view - Contents' );
SELECT set_eq( $$
SELECT empire_id , resource_name , empres_possessed , empres_owed
FROM bugs.dump_emp_resources_view
$$ , $$ VALUES (
_get_emp_name( 'empire1' ) , 'resource1' , 1 , 2
) $$ );
SELECT * FROM finish( );
ROLLBACK;

View file

@ -0,0 +1,11 @@
/*
* Test privileges on bugs.dump_emp_resources_view
*/
BEGIN;
SELECT plan( 1 );
SELECT diag_test_name( 'bugs.dump_emp_resources_view - Privileges' );
SELECT lives_ok( 'SELECT * FROM bugs.dump_emp_resources_view' );
SELECT * FROM finish( );
ROLLBACK;

View file

@ -0,0 +1,74 @@
package com.deepclone.lw.beans.bt.es;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import com.deepclone.lw.beans.bt.es.data.EmpireResourceInformation;
import com.deepclone.lw.testing.MockResultSet;
/**
* Tests for the {@link EmpireResourceInformationMapper} class.
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
public class TestEmpireResourceInformationMapper
{
/** Resource identifier used in tests */
private static final String TEST_ID = "Test";
/** "Owed" value used in tests */
private static final Double TEST_OWED = 1.0;
/** "Possessed" value used in tests */
private static final Double TEST_POSSESSED = 2.0;
/** The fake result set used in the tests */
private ResultSet resultSet;
/** The mapper used in the tests */
private EmpireResourceInformationMapper mapper;
/** Create the mapper and the contents of the fake result set */
@Before
@SuppressWarnings( "unchecked" )
public void setUp( )
{
this.mapper = new EmpireResourceInformationMapper( );
HashMap< String , Object > row = new HashMap< String , Object >( );
row.put( "resource_name" , TEST_ID );
row.put( "empres_possessed" , TEST_POSSESSED );
row.put( "empres_owed" , TEST_OWED );
this.resultSet = MockResultSet.create( new HashMap[] {
row
} );
}
/** Mapping a row */
@Test
public void testMapRow( )
throws SQLException
{
EmpireResourceInformation empRes;
this.resultSet.absolute( 1 );
empRes = this.mapper.mapRow( this.resultSet , 1 );
assertEquals( TEST_ID , empRes.getResource( ) );
assertEquals( TEST_POSSESSED , empRes.getPossessed( ) );
assertEquals( TEST_OWED , empRes.getOwed( ) );
}
}

View file

@ -0,0 +1,140 @@
package com.deepclone.lw.beans.bt.es.data;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import com.thoughtworks.xstream.XStream;
/**
* Tests for the {@link EmpireResourceInformation} class.
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
public class TestEmpireResourceInformation
{
/** Resource identifier used in tests */
private static final String TEST_ID = "Test";
/** "Owed" value used in tests */
private static final Double TEST_OWED = 1.0;
/** "Possessed" value used in tests */
private static final Double TEST_POSSESSED = 2.0;
/** Empire resource information instance used in tests */
private EmpireResourceInformation empRes;
/** Create the instance to be used in actual tests */
@Before
public void setUp( )
{
this.empRes = new EmpireResourceInformation( );
}
/** Default values are <code>null</code> */
@Test
public void testDefaultValues( )
{
assertNull( this.empRes.getResource( ) );
assertNull( this.empRes.getOwed( ) );
assertNull( this.empRes.getPossessed( ) );
}
/** Setting and reading the resource type */
@Test
public void testResource( )
{
this.empRes.setResource( TEST_ID );
assertEquals( TEST_ID , this.empRes.getResource( ) );
}
/** Setting the resource type to <code>null</code> */
@Test
public void testNullResource( )
{
try {
this.empRes.setResource( null );
fail( "InvalidDumpContentsException expected" );
} catch ( InvalidDumpContentsException exception ) {
assertEquals( EmpireResourceInformation.class , exception.getRecordType( ) );
assertEquals( "resource" , exception.getField( ) );
}
}
/** Setting and reading the amount of resources possessed */
@Test
public void testPossessed( )
{
this.empRes.setPossessed( TEST_POSSESSED );
assertEquals( TEST_POSSESSED , this.empRes.getPossessed( ) );
}
/** Setting and reading the amount of resources owed */
@Test
public void testOwed( )
{
this.empRes.setOwed( TEST_OWED );
assertEquals( TEST_OWED , this.empRes.getOwed( ) );
}
/** Serialising the instance to XML */
@Test
public void testXMLSerialisation( )
{
this.empRes.setResource( TEST_ID );
this.empRes.setOwed( TEST_OWED );
this.empRes.setPossessed( TEST_POSSESSED );
String serialised = this.createXStreamInstance( ).toXML( this.empRes );
assertNotNull( serialised );
assertTrue( serialised.startsWith( "<resource " ) );
assertTrue( serialised.endsWith( "/>" ) );
assertTrue( serialised.contains( " id=\"" + TEST_ID + "\"" ) );
assertTrue( serialised.contains( " owed=\"" + TEST_OWED + "\"" ) );
assertTrue( serialised.contains( " possessed=\"" + TEST_POSSESSED + "\"" ) );
}
/** Deserialising an instance from XML */
@Test
public void testXMLDeserialisation( )
{
String xml = "<resource id=\"" + TEST_ID + "\" owed=\"" + TEST_OWED.toString( ) + "\" possessed=\""
+ TEST_POSSESSED.toString( ) + "\" />";
Object deserialised = this.createXStreamInstance( ).fromXML( xml );
assertNotNull( deserialised );
assertEquals( EmpireResourceInformation.class , deserialised.getClass( ) );
this.empRes = (EmpireResourceInformation) deserialised;
assertEquals( TEST_ID , this.empRes.getResource( ) );
assertEquals( TEST_POSSESSED , this.empRes.getPossessed( ) );
assertEquals( TEST_OWED , this.empRes.getOwed( ) );
}
/**
* Create and set up the {@link XStream} instance used in the serialisation tests
*
* @return the {@link XStream} instance to use
*/
private XStream createXStreamInstance( )
{
XStream xstream = new XStream( );
xstream.processAnnotations( EmpireResourceInformation.class );
return xstream;
}
}