Technology definitions loader
* Added "dummy" data file for technologies (for now it simply copies the old, line-based technologies) and corresponding XML schema * Added missing SQL stored procedure to clear all dependencies and reverse dependencies from a technology * Added import classes, loader and import tool for the technology graph * Added tech graph import tool to post-build tests
This commit is contained in:
parent
c5464212bc
commit
1f3c7a9202
24 changed files with 1731 additions and 43 deletions
|
@ -33,6 +33,7 @@ EOF
|
||||||
java legacyworlds-server-main-*.jar --run-tool ImportText data/i18n-text.xml || exit 1
|
java legacyworlds-server-main-*.jar --run-tool ImportText data/i18n-text.xml || exit 1
|
||||||
java legacyworlds-server-main-*.jar --run-tool ImportResources data/resources.xml || exit 1
|
java legacyworlds-server-main-*.jar --run-tool ImportResources data/resources.xml || exit 1
|
||||||
java legacyworlds-server-main-*.jar --run-tool ImportTechs data/techs.xml || exit 1
|
java legacyworlds-server-main-*.jar --run-tool ImportTechs data/techs.xml || exit 1
|
||||||
|
java legacyworlds-server-main-*.jar --run-tool ImportTechGraph data/tech-graph.xml || exit 1
|
||||||
java legacyworlds-server-main-*.jar --run-tool ImportBuildables data/buildables.xml || exit 1
|
java legacyworlds-server-main-*.jar --run-tool ImportBuildables data/buildables.xml || exit 1
|
||||||
|
|
||||||
java legacyworlds-server-main-*.jar &
|
java legacyworlds-server-main-*.jar &
|
||||||
|
|
|
@ -324,6 +324,47 @@ GRANT EXECUTE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove all dependencies for a technology
|
||||||
|
* -----------------------------------------
|
||||||
|
*
|
||||||
|
* This stored procedure removes all dependencies and reverse dependencies for
|
||||||
|
* some technology.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* _technology The name of the technology
|
||||||
|
*/
|
||||||
|
DROP FUNCTION IF EXISTS defs.techdep_clear( TEXT );
|
||||||
|
CREATE FUNCTION defs.techdep_clear( _technology TEXT )
|
||||||
|
RETURNS VOID
|
||||||
|
LANGUAGE SQL
|
||||||
|
STRICT VOLATILE
|
||||||
|
SECURITY DEFINER
|
||||||
|
AS $techdep_clear$
|
||||||
|
|
||||||
|
DELETE FROM defs.technology_dependencies
|
||||||
|
WHERE technology_name_id = (
|
||||||
|
SELECT id FROM defs.strings
|
||||||
|
WHERE name = $1
|
||||||
|
);
|
||||||
|
|
||||||
|
DELETE FROM defs.technology_dependencies
|
||||||
|
WHERE technology_name_id_depends = (
|
||||||
|
SELECT id FROM defs.strings
|
||||||
|
WHERE name = $1
|
||||||
|
);
|
||||||
|
|
||||||
|
$techdep_clear$;
|
||||||
|
|
||||||
|
REVOKE EXECUTE
|
||||||
|
ON FUNCTION defs.techdep_clear( TEXT )
|
||||||
|
FROM PUBLIC;
|
||||||
|
GRANT EXECUTE
|
||||||
|
ON FUNCTION defs.techdep_clear( TEXT )
|
||||||
|
TO :dbuser;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- ********************************************************
|
-- ********************************************************
|
||||||
-- OLD CODE BELOW
|
-- OLD CODE BELOW
|
||||||
-- ********************************************************
|
-- ********************************************************
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Test the defs.techdep_clear() function
|
||||||
|
*/
|
||||||
|
BEGIN;
|
||||||
|
\i utils/strings.sql
|
||||||
|
-- Make the columns we don't use in the technology definition table NULL-able
|
||||||
|
ALTER TABLE defs.technologies
|
||||||
|
ALTER technology_category_id DROP NOT NULL ,
|
||||||
|
ALTER technology_discovery_id DROP NOT NULL ,
|
||||||
|
ALTER technology_description_id DROP NOT NULL ,
|
||||||
|
ALTER technology_price DROP NOT NULL ,
|
||||||
|
ALTER technology_points DROP NOT NULL;
|
||||||
|
|
||||||
|
-- Create strings to use as the technologies' names
|
||||||
|
SELECT _create_test_strings( 4 , 'tech' );
|
||||||
|
|
||||||
|
-- Insert the technologies
|
||||||
|
INSERT INTO defs.technologies ( technology_name_id )
|
||||||
|
VALUES ( _get_string( 'tech1' ) ) ,
|
||||||
|
( _get_string( 'tech2' ) ) ,
|
||||||
|
( _get_string( 'tech3' ) ) ,
|
||||||
|
( _get_string( 'tech4' ) );
|
||||||
|
|
||||||
|
-- Add a chain of dependencies
|
||||||
|
INSERT INTO defs.technology_dependencies(
|
||||||
|
technology_name_id , technology_name_id_depends
|
||||||
|
) VALUES ( _get_string( 'tech2' ) , _get_string( 'tech1' ) ) ,
|
||||||
|
( _get_string( 'tech3' ) , _get_string( 'tech2' ) ) ,
|
||||||
|
( _get_string( 'tech4' ) , _get_string( 'tech3' ) );
|
||||||
|
|
||||||
|
|
||||||
|
-- ***** TESTS BEGIN HERE *****
|
||||||
|
SELECT plan( 4 );
|
||||||
|
|
||||||
|
SELECT diag_test_name( 'defs.techdep_clear() - No failure on invalid technology name' );
|
||||||
|
SELECT lives_ok( $$
|
||||||
|
SELECT defs.techdep_clear( 'does not exist' )
|
||||||
|
$$ );
|
||||||
|
|
||||||
|
SELECT diag_test_name( 'defs.techdep_clear() - Successful call' );
|
||||||
|
SELECT lives_ok( $$
|
||||||
|
SELECT defs.techdep_clear( 'tech2' )
|
||||||
|
$$ );
|
||||||
|
|
||||||
|
SELECT diag_test_name( 'defs.techdep_clear() - Cleared technology has no dependencies' );
|
||||||
|
SELECT is_empty( $$
|
||||||
|
SELECT * FROM defs.technology_dependencies
|
||||||
|
WHERE technology_name_id = _get_string( 'tech2' );
|
||||||
|
$$ );
|
||||||
|
|
||||||
|
SELECT diag_test_name( 'defs.techdep_clear() - Cleared technology has no reverse dependencies' );
|
||||||
|
SELECT is_empty( $$
|
||||||
|
SELECT * FROM defs.technology_dependencies
|
||||||
|
WHERE technology_name_id_depends = _get_string( 'tech2' );
|
||||||
|
$$ );
|
||||||
|
|
||||||
|
SELECT * FROM finish( );
|
||||||
|
ROLLBACK;
|
|
@ -0,0 +1,13 @@
|
||||||
|
/*
|
||||||
|
* Test privileges on defs.techdep_remove()
|
||||||
|
*/
|
||||||
|
BEGIN;
|
||||||
|
SELECT plan( 1 );
|
||||||
|
|
||||||
|
SELECT diag_test_name( 'defs.techdep_clear() - EXECUTE privilege' );
|
||||||
|
SELECT lives_ok( $$
|
||||||
|
SELECT defs.techdep_clear( '' );
|
||||||
|
$$ );
|
||||||
|
|
||||||
|
SELECT * FROM finish( );
|
||||||
|
ROLLBACK;
|
42
legacyworlds-server-main/data/tech-graph.xml
Normal file
42
legacyworlds-server-main/data/tech-graph.xml
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<lw-tech-graph xmlns="http://www.deepclone.com/lw/b6/m2/tech-graph"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.deepclone.com/lw/b6/m2/tech-graph tech-graph.xsd">
|
||||||
|
|
||||||
|
<!-- Military technologies (cruisers, battle cruisers, dreadnoughts) -->
|
||||||
|
|
||||||
|
<technology name="cruisersTech" category="milTech"
|
||||||
|
description="cruisersTechDescription" discovery="cruisersTechDescription"
|
||||||
|
points="25000" cost="10000" />
|
||||||
|
|
||||||
|
<technology name="bCruisersTech" category="milTech"
|
||||||
|
description="bCruisersTechDescription" discovery="bCruisersTechDescription"
|
||||||
|
points="900000" cost="400000">
|
||||||
|
<depends-on>cruisersTech</depends-on>
|
||||||
|
</technology>
|
||||||
|
|
||||||
|
<technology name="dreadnoughtsTech" category="milTech"
|
||||||
|
description="dreadnoughtsTechDescription" discovery="dreadnoughtsTechDescription"
|
||||||
|
points="2250000" cost="1012500">
|
||||||
|
<depends-on>bCruisersTech</depends-on>
|
||||||
|
</technology>
|
||||||
|
|
||||||
|
<!-- Civilian technologies (industrial factories, corpse re-animation, bio-turrets -->
|
||||||
|
|
||||||
|
<technology name="indFactTech" category="civTech"
|
||||||
|
description="indFactTechDescription" discovery="indFactTechDescription"
|
||||||
|
points="10000" cost="5000" />
|
||||||
|
|
||||||
|
<technology name="reanimationTech" category="civTech"
|
||||||
|
description="reanimationTechDescription" discovery="reanimationTechDescription"
|
||||||
|
points="562500" cost="281250">
|
||||||
|
<depends-on>indFactTech</depends-on>
|
||||||
|
</technology>
|
||||||
|
|
||||||
|
<technology name="superTurretTech" category="civTech"
|
||||||
|
description="superTurretTechDescription" discovery="superTurretTechDescription"
|
||||||
|
points="1350000" cost="607500">
|
||||||
|
<depends-on>reanimationTech</depends-on>
|
||||||
|
</technology>
|
||||||
|
|
||||||
|
</lw-tech-graph>
|
35
legacyworlds-server-main/data/tech-graph.xsd
Normal file
35
legacyworlds-server-main/data/tech-graph.xsd
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<xs:schema xmlns="http://www.deepclone.com/lw/b6/m2/tech-graph"
|
||||||
|
targetNamespace="http://www.deepclone.com/lw/b6/m2/tech-graph"
|
||||||
|
xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
|
||||||
|
attributeFormDefault="unqualified">
|
||||||
|
|
||||||
|
<xs:element name="lw-tech-graph">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="technology" type="technology-description"
|
||||||
|
minOccurs="1" maxOccurs="unbounded">
|
||||||
|
</xs:element>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
<xs:simpleType name="positive-long">
|
||||||
|
<xs:restriction base="xs:long">
|
||||||
|
<xs:minExclusive value="0"></xs:minExclusive>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
<xs:complexType name="technology-description">
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="depends-on" type="xs:token" minOccurs="0"
|
||||||
|
maxOccurs="unbounded" />
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="name" use="required" type="xs:token" />
|
||||||
|
<xs:attribute name="category" use="required" type="xs:token" />
|
||||||
|
<xs:attribute name="description" use="required" type="xs:token" />
|
||||||
|
<xs:attribute name="discovery" use="required" type="xs:token" />
|
||||||
|
<xs:attribute name="cost" use="required" type="positive-long" />
|
||||||
|
<xs:attribute name="points" use="required" type="positive-long" />
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:schema>
|
|
@ -0,0 +1,326 @@
|
||||||
|
package com.deepclone.lw.cli;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.postgresql.util.PGobject;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.support.AbstractApplicationContext;
|
||||||
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
|
import org.springframework.context.support.FileSystemXmlApplicationContext;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
import org.springframework.transaction.support.TransactionCallback;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
|
import com.deepclone.lw.cli.xmlimport.TechnologyLoader;
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.techs.Technologies;
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.techs.Technology;
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.techs.TechnologyDefinitionResult;
|
||||||
|
import com.deepclone.lw.utils.StoredProc;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Technology graph import tool
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This class defines the body of the technology graph import tool. It loads the data file specified
|
||||||
|
* on the command line, validates it and then loads the technology definitions and dependencies into
|
||||||
|
* the database.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||||
|
*/
|
||||||
|
public class ImportTechGraph
|
||||||
|
extends CLITool
|
||||||
|
{
|
||||||
|
/** Logging system */
|
||||||
|
private final Logger logger = Logger.getLogger( ImportTechGraph.class );
|
||||||
|
|
||||||
|
/** File to read the definitions from */
|
||||||
|
private File file;
|
||||||
|
|
||||||
|
/** Spring transaction template */
|
||||||
|
private TransactionTemplate tTemplate;
|
||||||
|
|
||||||
|
/** Technology creation or update stored procedure */
|
||||||
|
private StoredProc fUocTechnology;
|
||||||
|
|
||||||
|
/** Stored procedure that removes all dependencies from a technology */
|
||||||
|
private StoredProc fTechdepClear;
|
||||||
|
|
||||||
|
/** Stored procedure that adds a dependency to a technology */
|
||||||
|
private StoredProc fTechdepAdd;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the Spring context
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Load the definition of the data source as a Spring context, then adds the transaction
|
||||||
|
* management component.
|
||||||
|
*
|
||||||
|
* @return the Spring application context
|
||||||
|
*/
|
||||||
|
private ClassPathXmlApplicationContext createContext( )
|
||||||
|
{
|
||||||
|
FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext( new String[] {
|
||||||
|
this.getDataSource( )
|
||||||
|
} );
|
||||||
|
ctx.refresh( );
|
||||||
|
|
||||||
|
return new ClassPathXmlApplicationContext( new String[] {
|
||||||
|
"configuration/transactions.xml"
|
||||||
|
} , true , ctx );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create database access templates
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Initialise the transaction template and the stored procedure wrappers.
|
||||||
|
*
|
||||||
|
* @param ctx
|
||||||
|
* the Spring application context
|
||||||
|
*/
|
||||||
|
private void createTemplates( ApplicationContext ctx )
|
||||||
|
{
|
||||||
|
DataSource dSource = ctx.getBean( DataSource.class );
|
||||||
|
PlatformTransactionManager tManager = ctx.getBean( PlatformTransactionManager.class );
|
||||||
|
|
||||||
|
this.fUocTechnology = new StoredProc( dSource , "defs" , "uoc_technology" )
|
||||||
|
.addParameter( "_name" , java.sql.Types.VARCHAR ).addParameter( "_category" , java.sql.Types.VARCHAR )
|
||||||
|
.addParameter( "_discovery" , java.sql.Types.VARCHAR )
|
||||||
|
.addParameter( "_description" , java.sql.Types.VARCHAR )
|
||||||
|
.addParameter( "_price" , java.sql.Types.BIGINT ).addParameter( "_points" , java.sql.Types.BIGINT )
|
||||||
|
.addOutput( "_result" , java.sql.Types.OTHER );
|
||||||
|
|
||||||
|
this.fTechdepClear = new StoredProc( dSource , "defs" , "techdep_clear" ).addParameter( "_tech" ,
|
||||||
|
java.sql.Types.VARCHAR );
|
||||||
|
|
||||||
|
this.fTechdepAdd = new StoredProc( dSource , "defs" , "techdep_add" )
|
||||||
|
.addParameter( "_dependent" , java.sql.Types.VARCHAR )
|
||||||
|
.addParameter( "_dependency" , java.sql.Types.VARCHAR ).addOutput( "_result" , java.sql.Types.OTHER );
|
||||||
|
|
||||||
|
this.tTemplate = new TransactionTemplate( tManager );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import all technology definitions
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Import all technology definitions from the top-level {@link Technologies}, creating a map of
|
||||||
|
* dependencies. Once all definitions have been imported, add all dependencies.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* the top level {@link Technologies} data instance
|
||||||
|
*
|
||||||
|
* @throws DataImportException
|
||||||
|
* when some technology definition or dependency cannot be imported
|
||||||
|
*/
|
||||||
|
private void importTechnologies( Technologies data )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
Map< String , List< String > > dependencies = new HashMap< String , List< String > >( );
|
||||||
|
for ( Technology technology : data ) {
|
||||||
|
this.importTechnologyDefinition( technology );
|
||||||
|
dependencies.put( technology.getName( ) , technology.getDependencies( ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( Map.Entry< String , List< String > > techDeps : dependencies.entrySet( ) ) {
|
||||||
|
for ( String dependency : techDeps.getValue( ) ) {
|
||||||
|
this.importDependency( techDeps.getKey( ) , dependency );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import a technology definition
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Import the definition, and if there was already a definition by that name, clear its
|
||||||
|
* dependencies.
|
||||||
|
*
|
||||||
|
* @param technology
|
||||||
|
* the definition to import
|
||||||
|
* @throws DataImportException
|
||||||
|
* when the update or creation stored procedure returns anything other than
|
||||||
|
* <code>CREATED</code> or <code>UPDATED</code>
|
||||||
|
*/
|
||||||
|
private void importTechnologyDefinition( Technology technology )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
this.logger.info( "Importing technology '" + technology.getName( ) + "'" );
|
||||||
|
|
||||||
|
TechnologyDefinitionResult result = this.getResultOf( this.fUocTechnology.execute( technology.getName( ) ,
|
||||||
|
technology.getCategory( ) , technology.getDiscovery( ) , technology.getDescription( ) ,
|
||||||
|
technology.getCost( ) , technology.getPoints( ) ) );
|
||||||
|
if ( result == TechnologyDefinitionResult.UPDATED ) {
|
||||||
|
this.fTechdepClear.execute( technology.getName( ) );
|
||||||
|
} else if ( result != TechnologyDefinitionResult.CREATED ) {
|
||||||
|
throw new DataImportException( "Error while importing technology '" + technology.getName( ) + "': "
|
||||||
|
+ result );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import a dependency between two technologies
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Attempt to add a dependency from a technology to another.
|
||||||
|
*
|
||||||
|
* @param dependent
|
||||||
|
* the dependent technology
|
||||||
|
* @param dependency
|
||||||
|
* the technology to depend on
|
||||||
|
*
|
||||||
|
* @throws DataImportException
|
||||||
|
* if dependency creation fails
|
||||||
|
*/
|
||||||
|
private void importDependency( String dependent , String dependency )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
this.logger.info( "Importing dependency from " + dependent + " to " + dependency );
|
||||||
|
|
||||||
|
TechnologyDefinitionResult result = this.getResultOf( this.fTechdepAdd.execute( dependent , dependency ) );
|
||||||
|
switch ( result ) {
|
||||||
|
case CREATED:
|
||||||
|
return;
|
||||||
|
case REDUNDANT:
|
||||||
|
throw new DataImportException( "( " + dependent + " -> " + dependency + " ) is redundant" );
|
||||||
|
case BAD_STRINGS:
|
||||||
|
throw new DataImportException( "( " + dependent + " -> " + dependency + " ): undefined technology" );
|
||||||
|
case CYCLE:
|
||||||
|
throw new DataImportException( "( " + dependent + " -> " + dependency + " ) would create a cycle" );
|
||||||
|
default:
|
||||||
|
throw new DataImportException( "( " + dependent + " -> " + dependency + " ): unexpected error code "
|
||||||
|
+ result );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for stored procedure results
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This method converts the map returned by one of the definition stored procedures into a
|
||||||
|
* {@link TechnologyDefinitionResult} value.
|
||||||
|
*
|
||||||
|
* @param spResult
|
||||||
|
* the return value of {@link StoredProc#execute(Object...)}
|
||||||
|
*
|
||||||
|
* @return the converted value of the _result field
|
||||||
|
*/
|
||||||
|
private TechnologyDefinitionResult getResultOf( Map< String , Object > spResult )
|
||||||
|
{
|
||||||
|
return TechnologyDefinitionResult.valueOf( ( (PGobject) spResult.get( "_result" ) ).getValue( ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the technology definitions import tool
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Loads the data file, the connects to the database and creates or updates all definitions.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run( )
|
||||||
|
{
|
||||||
|
Technologies data;
|
||||||
|
try {
|
||||||
|
data = new TechnologyLoader( this.file ).load( );
|
||||||
|
} catch ( DataImportException e ) {
|
||||||
|
this.logger.error( "Error while loading technology definitions" , e );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractApplicationContext ctx = this.createContext( );
|
||||||
|
this.createTemplates( ctx );
|
||||||
|
this.executeImportTransaction( data );
|
||||||
|
ToolBase.destroyContext( ctx );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the technology definitions importation transaction
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Run a transaction and execute the importation code inside it. Roll back if anything goes
|
||||||
|
* wrong.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* the {@link Technologies} definitions instance
|
||||||
|
*/
|
||||||
|
private void executeImportTransaction( final Technologies data )
|
||||||
|
{
|
||||||
|
boolean rv = this.tTemplate.execute( new TransactionCallback< Boolean >( ) {
|
||||||
|
@Override
|
||||||
|
public Boolean doInTransaction( TransactionStatus status )
|
||||||
|
{
|
||||||
|
boolean rv = ImportTechGraph.this.doTransaction( data );
|
||||||
|
if ( !rv ) {
|
||||||
|
status.setRollbackOnly( );
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
if ( rv ) {
|
||||||
|
this.logger.info( "Technology import successful" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import transaction body
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Import all definitions and handle exceptions.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* the {@link Technologies} definitions instance
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean doTransaction( Technologies data )
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
this.importTechnologies( data );
|
||||||
|
return true;
|
||||||
|
} catch ( RuntimeException e ) {
|
||||||
|
this.logger.error( "Caught runtime exception" , e );
|
||||||
|
} catch ( DataImportException e ) {
|
||||||
|
this.logger.error( e.getMessage( ) );
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the name of the definitions file
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Check the command line options, setting the definitions file accordingly.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean setOptions( String... options )
|
||||||
|
{
|
||||||
|
if ( options.length != 1 ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.file = new File( options[ 0 ] );
|
||||||
|
if ( ! ( this.file.isFile( ) && this.file.canRead( ) ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
package com.deepclone.lw.cli.xmlimport;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.techs.Technologies;
|
||||||
|
import com.thoughtworks.xstream.XStream;
|
||||||
|
import com.thoughtworks.xstream.XStreamException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Technology Loader
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This class can be used to load all technology definitions. It extracts them from the XML file and
|
||||||
|
* verifies them.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||||
|
*/
|
||||||
|
public class TechnologyLoader
|
||||||
|
{
|
||||||
|
/** The file to read the XML from */
|
||||||
|
private final File file;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise the loader
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* the XML file that contains the definitions
|
||||||
|
*/
|
||||||
|
public TechnologyLoader( File file )
|
||||||
|
{
|
||||||
|
this.file = file.getAbsoluteFile( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise the necessary XStream instance
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Initialise the XStream instance by processing the annotations of all the technology
|
||||||
|
* importable data classes.
|
||||||
|
*
|
||||||
|
* @return the XStream instance to use when loading the data
|
||||||
|
*/
|
||||||
|
private XStream initXStream( )
|
||||||
|
{
|
||||||
|
XStream xstream = new XStream( );
|
||||||
|
xstream.processAnnotations( Technologies.class );
|
||||||
|
return xstream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the technology definitions
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Load the XML file and process the definitions using XStream.
|
||||||
|
*
|
||||||
|
* @return the top-level importable data instance
|
||||||
|
*
|
||||||
|
* @throws DataImportException
|
||||||
|
* if reading from the file or parsing its contents fail
|
||||||
|
*/
|
||||||
|
private Technologies loadXMLFile( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
FileInputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream( this.file );
|
||||||
|
} catch ( FileNotFoundException e ) {
|
||||||
|
throw new DataImportException( "Unable to load technology definitions" , e );
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
XStream xstream = this.initXStream( );
|
||||||
|
return (Technologies) xstream.fromXML( fis );
|
||||||
|
} finally {
|
||||||
|
fis.close( );
|
||||||
|
}
|
||||||
|
} catch ( IOException e ) {
|
||||||
|
throw new DataImportException( "Input error while loading technology definitions" , e );
|
||||||
|
} catch ( XStreamException e ) {
|
||||||
|
throw new DataImportException( "XML error while loading technology definitions" , e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load and process technology definitions
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Attempt to load all technology definitions, ensure they are valid, then set the original
|
||||||
|
* file's path.
|
||||||
|
*
|
||||||
|
* @return the top-level importable data instance
|
||||||
|
*
|
||||||
|
* @throws DataImportException
|
||||||
|
* if loading or verifying the data fails
|
||||||
|
*/
|
||||||
|
public Technologies load( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
Technologies techs = this.loadXMLFile( );
|
||||||
|
techs.verifyData( );
|
||||||
|
techs.setReadFrom( this.file );
|
||||||
|
return techs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -64,9 +64,9 @@ public class BasicResource
|
||||||
throw new DataImportException( "Missing name string" );
|
throw new DataImportException( "Missing name string" );
|
||||||
}
|
}
|
||||||
if ( this.description == null || "".equals( this.description.trim( ) ) ) {
|
if ( this.description == null || "".equals( this.description.trim( ) ) ) {
|
||||||
throw new DataImportException( "Missing name string" );
|
throw new DataImportException( "Missing description string" );
|
||||||
}
|
}
|
||||||
if ( this.category != null && "".equals( this.description.trim( ) ) ) {
|
if ( this.category != null && "".equals( this.category.trim( ) ) ) {
|
||||||
throw new DataImportException( "Category invalid" );
|
throw new DataImportException( "Category invalid" );
|
||||||
}
|
}
|
||||||
if ( this.weight == null ) {
|
if ( this.weight == null ) {
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
package com.deepclone.lw.cli.xmlimport.data.techs;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.ImportableData;
|
||||||
|
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||||
|
import com.thoughtworks.xstream.annotations.XStreamImplicit;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Technology definitions data
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This class represents the contents of a technology definition XML file. It contains a list of
|
||||||
|
* technology definitions.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||||
|
*/
|
||||||
|
@SuppressWarnings( "serial" )
|
||||||
|
@XStreamAlias( "lw-tech-graph" )
|
||||||
|
public class Technologies
|
||||||
|
extends ImportableData
|
||||||
|
implements Iterable< Technology >
|
||||||
|
{
|
||||||
|
/** All present technology definitions */
|
||||||
|
@XStreamImplicit( itemFieldName = "technology" )
|
||||||
|
private final List< Technology > technologies = new LinkedList< Technology >( );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the technology data
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Check whether there is a list of technologies, then check each definition to make sure that
|
||||||
|
* it is valid and that its name is unique.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void verifyData( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
if ( this.technologies == null ) {
|
||||||
|
throw new DataImportException( "No technology definitions" );
|
||||||
|
}
|
||||||
|
|
||||||
|
HashSet< String > names = new HashSet< String >( );
|
||||||
|
for ( Technology tech : this.technologies ) {
|
||||||
|
tech.verifyData( );
|
||||||
|
this.checkUniqueItem( names , tech.getName( ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that the name of a technology is unique
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This helper method is used by {@link #verifyData()} to make sure technology names are unique.
|
||||||
|
*
|
||||||
|
* @param existing
|
||||||
|
* the existing set of names
|
||||||
|
* @param value
|
||||||
|
* the name to check
|
||||||
|
*
|
||||||
|
* @throws DataImportException
|
||||||
|
* if the name is already present in the set of existing names
|
||||||
|
*/
|
||||||
|
public void checkUniqueItem( HashSet< String > existing , String value )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
if ( existing.contains( value ) ) {
|
||||||
|
throw new DataImportException( "Duplicate technology name '" + value + "'" );
|
||||||
|
}
|
||||||
|
existing.add( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Technology definition iterator
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Grant access to the list of technologies in read-only mode.
|
||||||
|
*
|
||||||
|
* @return a read-only iterator on the list of technologies.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Iterator< Technology > iterator( )
|
||||||
|
{
|
||||||
|
return Collections.unmodifiableList( this.technologies ).iterator( );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,183 @@
|
||||||
|
package com.deepclone.lw.cli.xmlimport.data.techs;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.ImportableData;
|
||||||
|
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
|
||||||
|
import com.thoughtworks.xstream.annotations.XStreamImplicit;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A technology definition
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This class represents a technology definition that can be imported from the data file. It
|
||||||
|
* contains all required technology attributes, as well as a list of strings for the dependencies.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||||
|
*/
|
||||||
|
@SuppressWarnings( "serial" )
|
||||||
|
public class Technology
|
||||||
|
extends ImportableData
|
||||||
|
{
|
||||||
|
|
||||||
|
/** Identifier of the name string */
|
||||||
|
@XStreamAsAttribute
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/** Identifier of the category string */
|
||||||
|
@XStreamAsAttribute
|
||||||
|
private String category;
|
||||||
|
|
||||||
|
/** Identifier of the description string */
|
||||||
|
@XStreamAsAttribute
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/** Identifier of the string to display on technology discovery */
|
||||||
|
@XStreamAsAttribute
|
||||||
|
private String discovery;
|
||||||
|
|
||||||
|
/** Monetary cost of the technology */
|
||||||
|
@XStreamAsAttribute
|
||||||
|
private Long cost;
|
||||||
|
|
||||||
|
/** Required amount of research points */
|
||||||
|
@XStreamAsAttribute
|
||||||
|
private Long points;
|
||||||
|
|
||||||
|
/** List of technology name string identifiers describing the dependencies */
|
||||||
|
@XStreamImplicit( itemFieldName = "depends-on" )
|
||||||
|
private final List< String > dependencies = new LinkedList< String >( );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Technology definition verifier
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Make sure that all technology definition fields are both present and valid. If dependencies
|
||||||
|
* exist, also verify the names' validity.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void verifyData( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
if ( this.name == null || "".equals( this.name.trim( ) ) ) {
|
||||||
|
throw new DataImportException( "Missing name string" );
|
||||||
|
}
|
||||||
|
if ( this.category == null || "".equals( this.category.trim( ) ) ) {
|
||||||
|
throw new DataImportException( "Missing category string in " + this.name );
|
||||||
|
}
|
||||||
|
if ( this.description == null || "".equals( this.description.trim( ) ) ) {
|
||||||
|
throw new DataImportException( "Missing description string in " + this.name );
|
||||||
|
}
|
||||||
|
if ( this.discovery == null || "".equals( this.discovery.trim( ) ) ) {
|
||||||
|
throw new DataImportException( "Missing discovery string in " + this.name );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( this.points == null ) {
|
||||||
|
throw new DataImportException( "Missing research points in " + this.name );
|
||||||
|
} else if ( this.points <= 0 ) {
|
||||||
|
throw new DataImportException( "Invalid research points in " + this.name );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( this.cost == null ) {
|
||||||
|
throw new DataImportException( "Missing cost in " + this.name );
|
||||||
|
} else if ( this.cost <= 0 ) {
|
||||||
|
throw new DataImportException( "Invalid cost in " + this.name );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( this.dependencies != null ) {
|
||||||
|
for ( String dep : this.dependencies ) {
|
||||||
|
if ( dep == null || "".equals( dep.trim( ) ) ) {
|
||||||
|
throw new DataImportException( "Empty dependency name in " + this.name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the identifier of the name string.
|
||||||
|
*
|
||||||
|
* @return the identifier of the name string
|
||||||
|
*/
|
||||||
|
public String getName( )
|
||||||
|
{
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the identifier of the category string.
|
||||||
|
*
|
||||||
|
* @return the identifier of the category string
|
||||||
|
*/
|
||||||
|
public String getCategory( )
|
||||||
|
{
|
||||||
|
return this.category;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the identifier of the description string.
|
||||||
|
*
|
||||||
|
* @return the identifier of the description string
|
||||||
|
*/
|
||||||
|
public String getDescription( )
|
||||||
|
{
|
||||||
|
return this.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the identifier of the string to display on technology discovery.
|
||||||
|
*
|
||||||
|
* @return the identifier of the string to display on technology discovery
|
||||||
|
*/
|
||||||
|
public String getDiscovery( )
|
||||||
|
{
|
||||||
|
return this.discovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the monetary cost of the technology.
|
||||||
|
*
|
||||||
|
* @return the monetary cost of the technology
|
||||||
|
*/
|
||||||
|
public Long getCost( )
|
||||||
|
{
|
||||||
|
return this.cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the required amount of research points.
|
||||||
|
*
|
||||||
|
* @return the required amount of research points
|
||||||
|
*/
|
||||||
|
public Long getPoints( )
|
||||||
|
{
|
||||||
|
return this.points;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of technology name string identifiers describing the dependencies.
|
||||||
|
*
|
||||||
|
* @return the list of technology name string identifiers describing the dependencies
|
||||||
|
*/
|
||||||
|
public List< String > getDependencies( )
|
||||||
|
{
|
||||||
|
if ( this.dependencies == null ) {
|
||||||
|
return Collections.emptyList( );
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList( this.dependencies );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package com.deepclone.lw.cli.xmlimport.data.techs;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return codes for technology definition manipulation stored procedures
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This enumeration represents the various values which can be returned by the stored procedures
|
||||||
|
* which manipulate technology definitions and technology dependencies.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||||
|
*/
|
||||||
|
public enum TechnologyDefinitionResult {
|
||||||
|
|
||||||
|
/** The technology definition or dependency was created */
|
||||||
|
CREATED ,
|
||||||
|
|
||||||
|
/** The technology definition was updated */
|
||||||
|
UPDATED ,
|
||||||
|
|
||||||
|
/** The dependency was deleted */
|
||||||
|
DELETED ,
|
||||||
|
|
||||||
|
/** The specified dependency does not exist */
|
||||||
|
MISSING ,
|
||||||
|
|
||||||
|
/** One (or more) of the numeric parameters is invalid */
|
||||||
|
BAD_VALUE ,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name, description, discovery or category string identifiers were not valid string
|
||||||
|
* identifiers.
|
||||||
|
*/
|
||||||
|
BAD_STRINGS ,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The specified description and/or discovery string was in use by another technology.
|
||||||
|
*/
|
||||||
|
DUP_STRING ,
|
||||||
|
|
||||||
|
/** The dependency would cause a cycle */
|
||||||
|
CYCLE ,
|
||||||
|
|
||||||
|
/** The dependency would be redundant */
|
||||||
|
REDUNDANT
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<lw-tech-graph>
|
||||||
|
|
||||||
|
<does-not-exist />
|
||||||
|
|
||||||
|
</lw-tech-graph>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<lw-tech-graph xmlns="http://www.deepclone.com/lw/b6/m2/tech-graph"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.deepclone.com/lw/b6/m2/tech-graph tech-graph.xsd">
|
||||||
|
|
||||||
|
<technology />
|
||||||
|
|
||||||
|
</lw-tech-graph>
|
|
@ -0,0 +1,2 @@
|
||||||
|
This is not an XML file, obviously.
|
||||||
|
We'll make that even more confusing: <<<<<< & >>!!!
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<lw-tech-graph xmlns="http://www.deepclone.com/lw/b6/m2/tech-graph"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.deepclone.com/lw/b6/m2/tech-graph tech-graph.xsd">
|
||||||
|
|
||||||
|
<technology name="test" category="test" discovery="test"
|
||||||
|
description="test" cost="12" points="34" />
|
||||||
|
|
||||||
|
</lw-tech-graph>
|
|
@ -1,7 +1,11 @@
|
||||||
package com.deepclone.lw.cli.xmlimport;
|
package com.deepclone.lw.cli.xmlimport;
|
||||||
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -11,7 +15,6 @@ import org.junit.Test;
|
||||||
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
|
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
|
||||||
import com.deepclone.lw.cli.xmlimport.data.i18n.I18NText;
|
import com.deepclone.lw.cli.xmlimport.data.i18n.I18NText;
|
||||||
import com.deepclone.lw.cli.xmlimport.data.i18n.LanguageDefinition;
|
import com.deepclone.lw.cli.xmlimport.data.i18n.LanguageDefinition;
|
||||||
import com.deepclone.lw.cli.xmlimport.data.i18n.StringDefinition;
|
|
||||||
import com.thoughtworks.xstream.converters.ConversionException;
|
import com.thoughtworks.xstream.converters.ConversionException;
|
||||||
import com.thoughtworks.xstream.io.StreamException;
|
import com.thoughtworks.xstream.io.StreamException;
|
||||||
|
|
||||||
|
@ -129,22 +132,8 @@ public class TestI18NLoader
|
||||||
assertNotNull( text );
|
assertNotNull( text );
|
||||||
|
|
||||||
int lCount = 0;
|
int lCount = 0;
|
||||||
for ( LanguageDefinition ld : text ) {
|
for ( @SuppressWarnings( "unused" )
|
||||||
assertEquals( "test" , ld.getId( ) );
|
LanguageDefinition ld : text ) {
|
||||||
assertEquals( "test" , ld.getName( ) );
|
|
||||||
|
|
||||||
int tCount = 0;
|
|
||||||
for ( StringDefinition sd : ld ) {
|
|
||||||
assertEquals( "test" , sd.getId( ) );
|
|
||||||
try {
|
|
||||||
assertEquals( "test" , sd.getString( ).trim( ) );
|
|
||||||
} catch ( DataImportException e ) {
|
|
||||||
fail( "could not load string: " + e.getMessage( ) );
|
|
||||||
}
|
|
||||||
tCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals( 1 , tCount );
|
|
||||||
lCount++;
|
lCount++;
|
||||||
}
|
}
|
||||||
assertEquals( 1 , lCount );
|
assertEquals( 1 , lCount );
|
||||||
|
|
|
@ -14,7 +14,6 @@ import org.junit.Test;
|
||||||
|
|
||||||
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
|
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
|
||||||
import com.deepclone.lw.cli.xmlimport.data.resources.BasicResource;
|
import com.deepclone.lw.cli.xmlimport.data.resources.BasicResource;
|
||||||
import com.deepclone.lw.cli.xmlimport.data.resources.NaturalResource;
|
|
||||||
import com.deepclone.lw.cli.xmlimport.data.resources.Resources;
|
import com.deepclone.lw.cli.xmlimport.data.resources.Resources;
|
||||||
import com.thoughtworks.xstream.converters.ConversionException;
|
import com.thoughtworks.xstream.converters.ConversionException;
|
||||||
import com.thoughtworks.xstream.io.StreamException;
|
import com.thoughtworks.xstream.io.StreamException;
|
||||||
|
@ -127,27 +126,8 @@ public class TestResourceLoader
|
||||||
// Not sure if this is the best way to code for the two different resource types...
|
// Not sure if this is the best way to code for the two different resource types...
|
||||||
int rCount = 0;
|
int rCount = 0;
|
||||||
|
|
||||||
for ( BasicResource br : resources ) {
|
for ( @SuppressWarnings( "unused" )
|
||||||
if ( rCount == 0 ) {
|
BasicResource br : resources ) {
|
||||||
assertEquals( "money" , br.getName( ) );
|
|
||||||
assertEquals( "moneyDescription" , br.getDescription( ) );
|
|
||||||
assertEquals( new Integer( 0 ) , br.getWeight( ) );
|
|
||||||
assertEquals( null , br.getCategory( ) );
|
|
||||||
} else if ( rCount == 1 ) {
|
|
||||||
// This isn't retarded is it?
|
|
||||||
NaturalResource nr = (NaturalResource) br;
|
|
||||||
assertEquals( "titanium" , nr.getName( ) );
|
|
||||||
assertEquals( "titaniumDescription" , nr.getDescription( ) );
|
|
||||||
assertEquals( new Integer( 1 ) , nr.getWeight( ) );
|
|
||||||
assertEquals( "minerals" , nr.getCategory( ) );
|
|
||||||
assertEquals( new Double( 0.8 ) , nr.getPresenceProbability( ) );
|
|
||||||
assertEquals( new Double( 5000 ) , nr.getQuantity( ).getAverage( ) );
|
|
||||||
assertEquals( new Double( 1500 ) , nr.getQuantity( ).getDeviation( ) );
|
|
||||||
assertEquals( new Double( 0.1 ) , nr.getDifficulty( ).getAverage( ) );
|
|
||||||
assertEquals( new Double( 0.05 ) , nr.getDifficulty( ).getDeviation( ) );
|
|
||||||
assertEquals( new Double( 0.4 ) , nr.getRecovery( ).getAverage( ) );
|
|
||||||
assertEquals( new Double( 0.05 ) , nr.getRecovery( ).getDeviation( ) );
|
|
||||||
}
|
|
||||||
rCount++;
|
rCount++;
|
||||||
}
|
}
|
||||||
assertEquals( 2 , rCount );
|
assertEquals( 2 , rCount );
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
package com.deepclone.lw.cli.xmlimport;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.techs.Technologies;
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.techs.Technology;
|
||||||
|
import com.thoughtworks.xstream.converters.ConversionException;
|
||||||
|
import com.thoughtworks.xstream.io.StreamException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the {@link TechnologyLoader} class.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||||
|
*/
|
||||||
|
public class TestTechnologyLoader
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Try initialising the loader with a <code>null</code> file instance.
|
||||||
|
*
|
||||||
|
* @throws NullPointerException
|
||||||
|
* when the constructor is executed
|
||||||
|
*/
|
||||||
|
@Test( expected = NullPointerException.class )
|
||||||
|
public void testNullFile( )
|
||||||
|
throws NullPointerException
|
||||||
|
{
|
||||||
|
new TechnologyLoader( null );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Try loading a file that does not exist */
|
||||||
|
@Test
|
||||||
|
public void testMissingFile( )
|
||||||
|
{
|
||||||
|
TechnologyLoader loader = new TechnologyLoader( new File( "does-not-exist" ) );
|
||||||
|
try {
|
||||||
|
loader.load( );
|
||||||
|
} catch ( DataImportException e ) {
|
||||||
|
assertTrue( "cause is a" + e.getCause( ).getClass( ).getName( ) , e.getCause( ) instanceof IOException );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fail( "no exception after trying to load a missing file" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Try loading a file that contains something that is not XML. */
|
||||||
|
@Test
|
||||||
|
public void testBadXML( )
|
||||||
|
{
|
||||||
|
TechnologyLoader loader = new TechnologyLoader( new File( "TestFiles/technology-loader/bad-xml.xml" ) );
|
||||||
|
try {
|
||||||
|
loader.load( );
|
||||||
|
} catch ( DataImportException e ) {
|
||||||
|
assertTrue( "cause is a " + e.getCause( ).getClass( ).getName( ) , e.getCause( ) instanceof StreamException );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fail( "no exception after loading stuff that isn't XML" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test loading a file that contains XML but which cannot be deserialised to a
|
||||||
|
* {@link Technologies} instance.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testBadContents( )
|
||||||
|
{
|
||||||
|
TechnologyLoader loader = new TechnologyLoader( new File( "TestFiles/technology-loader/bad-contents.xml" ) );
|
||||||
|
try {
|
||||||
|
loader.load( );
|
||||||
|
} catch ( DataImportException e ) {
|
||||||
|
assertTrue( "cause is a " + e.getCause( ).getClass( ).getName( ) ,
|
||||||
|
e.getCause( ) instanceof ConversionException );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fail( "no exception after loading bad XML" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try loading a file that contains valid XML for a {@link Technologies} instance with semantic
|
||||||
|
* errors.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testBadData( )
|
||||||
|
{
|
||||||
|
TechnologyLoader loader = new TechnologyLoader( new File( "TestFiles/technology-loader/bad-data.xml" ) );
|
||||||
|
try {
|
||||||
|
loader.load( );
|
||||||
|
} catch ( DataImportException e ) {
|
||||||
|
assertNull( e.getCause( ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fail( "no exception after loading bad data" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Try loading valid data, make sure that it contains one record */
|
||||||
|
@Test
|
||||||
|
public void testGoodData( )
|
||||||
|
{
|
||||||
|
TechnologyLoader loader = new TechnologyLoader( new File( "TestFiles/technology-loader/good-data.xml" ) );
|
||||||
|
Technologies technologies;
|
||||||
|
try {
|
||||||
|
technologies = loader.load( );
|
||||||
|
} catch ( DataImportException e ) {
|
||||||
|
fail( "could not load valid file" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assertNotNull( technologies );
|
||||||
|
|
||||||
|
int rCount = 0;
|
||||||
|
for ( @SuppressWarnings( "unused" )
|
||||||
|
Technology tech : technologies ) {
|
||||||
|
rCount++;
|
||||||
|
}
|
||||||
|
assertEquals( 1 , rCount );
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ import com.thoughtworks.xstream.XStreamException;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
abstract public class BaseTest
|
abstract class BaseTest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Escape &, < and > in XML strings
|
* Escape &, < and > in XML strings
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
package com.deepclone.lw.cli.xmlimport.data.techs;
|
||||||
|
|
||||||
|
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.ImportableData;
|
||||||
|
import com.thoughtworks.xstream.XStream;
|
||||||
|
import com.thoughtworks.xstream.XStreamException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for testing technology importation
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This class is used as a parent for tests of the technology import structures. It includes the
|
||||||
|
* code used to actually create these technology definitions, as this can normally only be done
|
||||||
|
* through XStream.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class BaseTest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Escape &, < and > in XML strings
|
||||||
|
*
|
||||||
|
* @param string
|
||||||
|
* the string to escape
|
||||||
|
*
|
||||||
|
* @return the escaped string
|
||||||
|
*/
|
||||||
|
private String xmlString( String string )
|
||||||
|
{
|
||||||
|
return string.replace( "&" , "&" ).replace( "<" , "<" ).replace( ">" , ">" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape &, < and >, ' and " in XML strings
|
||||||
|
*
|
||||||
|
* @param string
|
||||||
|
* the string to escape
|
||||||
|
*
|
||||||
|
* @return the escaped string
|
||||||
|
*/
|
||||||
|
private String quoteString( String string )
|
||||||
|
{
|
||||||
|
return "\"" + this.xmlString( string ).replace( "\"" , """ ).replace( "'" , "'" ) + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the XML code for a technology definition
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This method generates the XML code for a technology definition, which can then be imported
|
||||||
|
* using XStream into a {@link Technology} instance. It is capable of generating instances with
|
||||||
|
* various fields set to <code>null</code>.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* identifier of the technology's name string
|
||||||
|
* @param category
|
||||||
|
* identifier of the technology's category string
|
||||||
|
* @param discovery
|
||||||
|
* identifier of the technology's discovery string
|
||||||
|
* @param description
|
||||||
|
* identifier of the technology's description string
|
||||||
|
* @param cost
|
||||||
|
* monetary cost of implementing the technology
|
||||||
|
* @param points
|
||||||
|
* amount of research points required
|
||||||
|
* @param dependencies
|
||||||
|
* dependencies as an array of strings
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected String createTechnology( String name , String category , String discovery , String description ,
|
||||||
|
Long cost , Long points , String... dependencies )
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder( "<technology" );
|
||||||
|
|
||||||
|
if ( name != null ) {
|
||||||
|
builder.append( " name=" ).append( this.quoteString( name ) );
|
||||||
|
}
|
||||||
|
if ( category != null ) {
|
||||||
|
builder.append( " category=" ).append( this.quoteString( category ) );
|
||||||
|
}
|
||||||
|
if ( discovery != null ) {
|
||||||
|
builder.append( " discovery=" ).append( this.quoteString( discovery ) );
|
||||||
|
}
|
||||||
|
if ( description != null ) {
|
||||||
|
builder.append( " description=" ).append( this.quoteString( description ) );
|
||||||
|
}
|
||||||
|
if ( cost != null ) {
|
||||||
|
builder.append( " cost=\"" ).append( cost ).append( "\"" );
|
||||||
|
}
|
||||||
|
if ( points != null ) {
|
||||||
|
builder.append( " points=\"" ).append( points ).append( "\"" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( dependencies.length == 0 ) {
|
||||||
|
builder.append( " />" );
|
||||||
|
} else {
|
||||||
|
builder.append( ">" );
|
||||||
|
for ( String dep : dependencies ) {
|
||||||
|
builder.append( "<depends-on>" );
|
||||||
|
if ( dep != null ) {
|
||||||
|
builder.append( this.xmlString( dep ) );
|
||||||
|
}
|
||||||
|
builder.append( "</depends-on>" );
|
||||||
|
}
|
||||||
|
builder.append( "</technology>" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.toString( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the XML code for a top-level technology definition element
|
||||||
|
*
|
||||||
|
* @param resources
|
||||||
|
* XML definitions of technologies
|
||||||
|
*
|
||||||
|
* @return the top-level element's XML code
|
||||||
|
*/
|
||||||
|
protected String createTopLevel( String... technologies )
|
||||||
|
{
|
||||||
|
StringBuilder str = new StringBuilder( );
|
||||||
|
str.append( "<lw-tech-graph>" );
|
||||||
|
for ( String technology : technologies ) {
|
||||||
|
str.append( technology );
|
||||||
|
}
|
||||||
|
str.append( "</lw-tech-graph>" );
|
||||||
|
return str.toString( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the necessary XStream instance
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Initialise an XStream instance and set it up so it can process technology data definitions.
|
||||||
|
* This includes annotation processing, of course, but also generating an alias allowing the
|
||||||
|
* <technology> tag to be recognised on its own.
|
||||||
|
*/
|
||||||
|
private XStream createXStreamInstance( )
|
||||||
|
{
|
||||||
|
XStream xstream = new XStream( );
|
||||||
|
xstream.processAnnotations( Technologies.class );
|
||||||
|
xstream.alias( "technology" , Technology.class );
|
||||||
|
return xstream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a resource object from its XML code
|
||||||
|
*
|
||||||
|
* @param xml
|
||||||
|
* the XML code
|
||||||
|
* @param cls
|
||||||
|
* the class of the object
|
||||||
|
*
|
||||||
|
* @return the object that was created from the code
|
||||||
|
*
|
||||||
|
* @throws ClassCastException
|
||||||
|
* if the code corresponds to some other type of object
|
||||||
|
* @throws XStreamException
|
||||||
|
* if some error occurred while deserialising the object
|
||||||
|
*/
|
||||||
|
protected < T extends ImportableData > T createObject( String xml , Class< T > cls )
|
||||||
|
throws ClassCastException , XStreamException
|
||||||
|
{
|
||||||
|
return cls.cast( this.createXStreamInstance( ).fromXML( xml ) );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
package com.deepclone.lw.cli.xmlimport.data.techs;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the {@link Technologies} class
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||||
|
*/
|
||||||
|
public class TestTechnologies
|
||||||
|
extends BaseTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test loading an empty list of technologies
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* {@link Technologies#iterator()} will throw {@link NullPointerException} when there are no
|
||||||
|
* definitions. Use that to determine if it is empty.
|
||||||
|
*/
|
||||||
|
@Test( expected = NullPointerException.class )
|
||||||
|
public void testEmpty( )
|
||||||
|
{
|
||||||
|
String defs = this.createTopLevel( );
|
||||||
|
Technologies techs = this.createObject( defs , Technologies.class );
|
||||||
|
techs.iterator( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test loading a list of technologies
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testTechs( )
|
||||||
|
{
|
||||||
|
String tDef = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L );
|
||||||
|
String defs = this.createTopLevel( tDef );
|
||||||
|
Technologies techs = this.createObject( defs , Technologies.class );
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for ( Technology technology : techs ) {
|
||||||
|
assertNotNull( technology );
|
||||||
|
assertEquals( 0 , i );
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test verifying an empty list of technologies
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyEmpty( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String defs = this.createTopLevel( );
|
||||||
|
Technologies techs = this.createObject( defs , Technologies.class );
|
||||||
|
techs.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test verifying a list of technologies with an invalid technology in it
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyInvalid( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String tDef = this.createTechnology( null , "category" , "discovery" , "description" , 12L , 34L );
|
||||||
|
String defs = this.createTopLevel( tDef );
|
||||||
|
Technologies techs = this.createObject( defs , Technologies.class );
|
||||||
|
techs.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test verifying a valid list of technologies
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testVerifyOk( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String tDef = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L );
|
||||||
|
String defs = this.createTopLevel( tDef );
|
||||||
|
Technologies techs = this.createObject( defs , Technologies.class );
|
||||||
|
techs.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,329 @@
|
||||||
|
package com.deepclone.lw.cli.xmlimport.data.techs;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the {@link Technology} class
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||||
|
*/
|
||||||
|
public class TestTechnology
|
||||||
|
extends BaseTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test loading a definition with no dependencies
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testLoadNoDeps( )
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
|
||||||
|
assertNotNull( technology );
|
||||||
|
assertEquals( "name" , technology.getName( ) );
|
||||||
|
assertEquals( "category" , technology.getCategory( ) );
|
||||||
|
assertEquals( "discovery" , technology.getDiscovery( ) );
|
||||||
|
assertEquals( "description" , technology.getDescription( ) );
|
||||||
|
assertEquals( new Long( 12 ) , technology.getCost( ) );
|
||||||
|
assertEquals( new Long( 34 ) , technology.getPoints( ) );
|
||||||
|
|
||||||
|
assertNotNull( technology.getDependencies( ) );
|
||||||
|
assertTrue( technology.getDependencies( ).isEmpty( ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test loading a definition with dependencies
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testLoadDeps( )
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L ,
|
||||||
|
"dep1" , "dep2" );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
|
||||||
|
assertNotNull( technology );
|
||||||
|
assertEquals( "name" , technology.getName( ) );
|
||||||
|
assertEquals( "category" , technology.getCategory( ) );
|
||||||
|
assertEquals( "discovery" , technology.getDiscovery( ) );
|
||||||
|
assertEquals( "description" , technology.getDescription( ) );
|
||||||
|
assertEquals( new Long( 12 ) , technology.getCost( ) );
|
||||||
|
assertEquals( new Long( 34 ) , technology.getPoints( ) );
|
||||||
|
|
||||||
|
assertNotNull( technology.getDependencies( ) );
|
||||||
|
assertEquals( 2 , technology.getDependencies( ).size( ) );
|
||||||
|
assertEquals( "dep1" , technology.getDependencies( ).get( 0 ) );
|
||||||
|
assertEquals( "dep2" , technology.getDependencies( ).get( 1 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the name is null
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyNameNull( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( null , "category" , "discovery" , "description" , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the name is empty
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyNameEmpty( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "" , "category" , "discovery" , "description" , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the name consists of spaces only
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyNameSpaces( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( " " , "category" , "discovery" , "description" , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the category is null
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyCategoryNull( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , null , "discovery" , "description" , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the category is empty
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyCategoryEmpty( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "" , "discovery" , "description" , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the category consists of spaces only
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyCategorySpaces( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , " " , "discovery" , "description" , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the discovery string is null
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyDiscoveryNull( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , null , "description" , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the discovery string is empty
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyDiscoveryEmpty( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "" , "description" , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the discovery string consists of spaces only
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyDiscoverySpaces( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , " " , "description" , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the description is null
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyDescriptionNull( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , null , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the description is empty
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyDescriptionEmpty( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , "" , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the description consists of spaces only
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyDescriptionSpaces( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , " " , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the cost is null
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyCostNull( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , null , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the cost is 0
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyCostZero( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 0L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the amount of points is null
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyPointsNull( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , null );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when the amount of points is 0
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyPointsZero( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 0L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} on a valid definition with no dependencies
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testVerifyValidNoDeps( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when a dependency is empty
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyDepsEmpty( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L , "" );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} when a dependency consists of spaces only
|
||||||
|
*/
|
||||||
|
@Test( expected = DataImportException.class )
|
||||||
|
public void testVerifyDepsSpaces( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L ,
|
||||||
|
" " );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test {@link Technology#verifyData()} on a valid definition with dependencies
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testVerifyValidDeps( )
|
||||||
|
throws DataImportException
|
||||||
|
{
|
||||||
|
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L ,
|
||||||
|
"dep1" , "dep2" );
|
||||||
|
Technology technology = this.createObject( definition , Technology.class );
|
||||||
|
technology.verifyData( );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -41,6 +41,8 @@ from the root of the server's distribution:
|
||||||
--run-tool ImportText data/i18n-text.xml
|
--run-tool ImportText data/i18n-text.xml
|
||||||
java -jar legacyworlds-server-main-1.0.0-0.jar \
|
java -jar legacyworlds-server-main-1.0.0-0.jar \
|
||||||
--run-tool ImportTechs data/techs.xml
|
--run-tool ImportTechs data/techs.xml
|
||||||
|
java -jar legacyworlds-server-main-1.0.0-0.jar \
|
||||||
|
--run-tool ImportTechGraph data/tech-graph.xml
|
||||||
java -jar legacyworlds-server-main-1.0.0-0.jar \
|
java -jar legacyworlds-server-main-1.0.0-0.jar \
|
||||||
--run-tool ImportResources data/resources.xml
|
--run-tool ImportResources data/resources.xml
|
||||||
java -jar legacyworlds-server-main-1.0.0-0.jar \
|
java -jar legacyworlds-server-main-1.0.0-0.jar \
|
||||||
|
|
Reference in a new issue