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
legacyworlds-server-main
data
src/main/java/com/deepclone/lw/cli
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" );
|
||||
}
|
||||
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" );
|
||||
}
|
||||
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
|
||||
|
||||
}
|
Reference in a new issue