Compare commits

...

29 Commits

Author SHA1 Message Date
LO Kam Tao Leo 977306c640 Retriving SMART data 3 years ago
LO Kam Tao Leo 5de7b39c8b Add a helper class 3 years ago
LO Kam Tao Leo 7f6dc009ba Importing SMART data 3 years ago
LO Kam Tao Leo 4e69fd8a1d Additional test case 3 years ago
LO Kam Tao Leo 3d930cd506 Fixing incorrect handling of berth offset 3 years ago
LO Kam Tao Leo 2b3171271e Parsing data 3 years ago
LO Kam Tao Leo 952208dff1 Additional test case 3 years ago
LO Kam Tao Leo a63dd871bd Code refactoring 3 years ago
LO Kam Tao Leo be38739c23 Basic operation on SMART 3 years ago
LO Kam Tao Leo 32fdd0e4ae Refactor code and adding SMART data 3 years ago
LO Kam Tao Leo 3400f84628 Basic search for CORPUS 3 years ago
LO Kam Tao Leo 9a46a5455a Foundation for a more flexible search. 3 years ago
LO Kam Tao Leo b8095f476c Refactoring for the incorrect package 3 years ago
LO Kam Tao Leo 1148a15f1a Extra function for handling CORPUS 3 years ago
LO Kam Tao Leo 71be192408 Job to insert the records. 3 years ago
LO Kam Tao Leo 260a5abbda Triggering the ReferenceDataJob if enabled in config 3 years ago
LO Kam Tao Leo a634fcc886 Insertion of CORPUS 3 years ago
LO Kam Tao Leo 0cdb689f09 Skeleton for cron job 3 years ago
LO Kam Tao Leo 4818efef9d Merge branch 'feature-db-basic' into feature-cron-basic 3 years ago
LO Kam Tao Leo 8111c693ce Basic Dao structure and MetadataDao 3 years ago
LO Kam Tao Leo dbbfb5609c Added dependency 3 years ago
LO Kam Tao Leo a5aa9f4aa1 Basic database function 3 years ago
LO Kam Tao Leo e1532f5179 Adding dependency and added url construct 3 years ago
LO Kam Tao Leo b0b5a2e173 Skeleton code to initialize the DatabaseManager 3 years ago
LO Kam Tao Leo c44f6fe63b Skeleton code for database 3 years ago
LO Kam Tao Leo b2e6f020b0 Updated unit test 3 years ago
LO Kam Tao Leo f866ca44f9 Basic unit test 3 years ago
LO Kam Tao Leo 0d1bed4265 Loading configuration 3 years ago
LO Kam Tao Leo 9dc80d90f2 Skeleton 3 years ago
  1. 7
      .gitignore
  2. 79
      .idea/workspace.xml
  3. 68
      pom.xml
  4. 131
      src/main/java/org/leolo/nrdatad/App.java
  5. 127
      src/main/java/org/leolo/nrdatad/ConfigurationManager.java
  6. 23
      src/main/java/org/leolo/nrdatad/Constants.java
  7. 102
      src/main/java/org/leolo/nrdatad/cron/ReferenceDataJob.java
  8. 48
      src/main/java/org/leolo/nrdatad/db/BaseDao.java
  9. 146
      src/main/java/org/leolo/nrdatad/db/CorpusDao.java
  10. 19
      src/main/java/org/leolo/nrdatad/db/DatabaseManager.java
  11. 42
      src/main/java/org/leolo/nrdatad/db/MetadataDao.java
  12. 65
      src/main/java/org/leolo/nrdatad/db/ParameterStore.java
  13. 17
      src/main/java/org/leolo/nrdatad/db/SearchMode.java
  14. 229
      src/main/java/org/leolo/nrdatad/db/SmartDao.java
  15. 379
      src/main/java/org/leolo/nrdatad/db/mariadb/CorpusDao.java
  16. 80
      src/main/java/org/leolo/nrdatad/db/mariadb/DatabaseManager.java
  17. 116
      src/main/java/org/leolo/nrdatad/db/mariadb/MetadataDao.java
  18. 322
      src/main/java/org/leolo/nrdatad/db/mariadb/SmartDao.java
  19. 115
      src/main/java/org/leolo/nrdatad/model/Corpus.java
  20. 180
      src/main/java/org/leolo/nrdatad/model/Smart.java
  21. 31
      src/main/java/org/leolo/nrdatad/model/SmartEvent.java
  22. 63
      src/main/java/org/leolo/nrdatad/model/SmartStepType.java
  23. 63
      src/main/java/org/leolo/nrdatad/util/HttpUtil.java
  24. 17
      src/main/java/org/leolo/nrdatad/util/JSONUtil.java
  25. 25
      src/main/java/org/leolo/nrdatad/util/Range.java
  26. 22
      src/main/resources/log4j2.xml
  27. 5
      src/test/java/org/leolo/nrdatad/AppTest.java
  28. 92
      src/test/java/org/leolo/nrdatad/ConfigurationTest.java
  29. 270
      src/test/java/org/leolo/nrdatad/ReferenceDataParserTest.java
  30. 29
      src/test/java/org/leolo/nrdatad/SmartEnumTest.java
  31. 35
      src/test/java/org/leolo/nrdatad/UtilTest.java
  32. 42
      src/test/java/org/leolo/nrdatad/db/test/DatabaseManager.java
  33. 40
      src/test/java/org/leolo/nrdatad/db/test/MetadataDao.java
  34. 20
      src/test/java/org/leolo/nrdatad/util/RangeTest.java

7
.gitignore vendored

@ -36,3 +36,10 @@ build/
### Mac OS ###
.DS_Store
### Configuration file
/nrdatad.conf
ri_log*
test-*.tmp
.idea/workspace.xml
.idea/

79
.idea/workspace.xml

@ -1,79 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="b9554e7b-3332-419c-960c-8bfbee0d5311" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/aws.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/pom.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/org/leolo/nrdatad/App.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/test/java/org/leolo/AppTest.java" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="ProjectId" id="2GCtKiOdhwqUrJrlolmjYzZXLwa" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectViewState">
<option name="flattenPackages" value="true" />
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"WebServerToolWindowFactoryState": "false"
}
}]]></component>
<component name="RunManager">
<configuration name="Main" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.leolo.nrdatad.App" />
<module name="nr-data-damon" />
<extension name="software.aws.toolkits.jetbrains.core.execution.JavaAwsConnectionExtension">
<option name="credential" />
<option name="region" />
<option name="useCurrentConnection" value="false" />
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="b9554e7b-3332-419c-960c-8bfbee0d5311" name="Changes" comment="" />
<created>1665904334835</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1665904334835</updated>
<workItem from="1665904336661" duration="319000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
</project>

68
pom.xml

@ -14,8 +14,9 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<ver-log4j2>2.19.0</ver-log4j2>
</properties>
<dependencies>
@ -25,6 +26,58 @@
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${ver-log4j2}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${ver-log4j2}</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>2.7.6</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20220924</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${ver-log4j2}</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20220924</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
</dependencies>
<build>
@ -71,5 +124,16 @@
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

131
src/main/java/org/leolo/nrdatad/App.java

@ -1,11 +1,140 @@
package org.leolo.nrdatad;
import org.apache.commons.cli.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.leolo.nrdatad.db.CorpusDao;
import org.leolo.nrdatad.db.DatabaseManager;
import org.leolo.nrdatad.cron.ReferenceDataJob;
import org.leolo.nrdatad.model.Corpus;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.Collection;
/**
* Hello world!
*
*/
public class App {
Logger log = LogManager.getLogger();
private ConfigurationManager config = ConfigurationManager.getInstance();
private Scheduler scheduler;
public static void main( String[] args ) {
System.out.println( "Hello World!" );
Option confFile = Option.builder()
.required(false)
.hasArg(true)
.argName("fileName")
.option("c")
.longOpt("config-file")
.build();
Options opts = new Options();
opts.addOption(confFile);
String confPath = "nrdatad.conf";
try {
CommandLine cli = new DefaultParser().parse(opts, args);
if(cli.hasOption(confFile)){
confPath = cli.getOptionValue(confFile);
}
} catch (ParseException e) {
throw new RuntimeException(e);
}
new App().run(confPath);
}
private void run(String configPath){
log.always().log("System Started.");
try {
config.loadConfiguration(configPath);
} catch (IOException e) {
log.atError().withThrowable(e).log("Unable to load confog file");
return;
}
// log.atDebug()
if(config.getProperty("general.debug","false").equals("true")){
for(String key:config.stringPropertyNames()){
if(key.endsWith("pwd")){
log.atDebug().log("Config: {} : ****({} chars)", key, config.getProperty(key).length());
}else{
log.atDebug().log("Config: {} : {}", key, config.getProperty(key));
}
}
}
String databaseManagerClass = config.getProperty("db.manager","org.leolo.nrdatad.db.DatabaseManager");
log.atInfo().log("Creating database manager {}", databaseManagerClass);
try {
config.setDatabaseManager((DatabaseManager) Class.forName(databaseManagerClass).getConstructor().newInstance());
} catch (
InstantiationException|IllegalAccessException|InvocationTargetException|
NoSuchMethodException|ClassNotFoundException e
) {
log.atFatal().log("Unable to create instance of {}", databaseManagerClass);
System.exit(1);
return;
} catch (ClassCastException e){
log.atFatal().log("{} is not a DatabaseManager", databaseManagerClass);
System.exit(1);
return;
}
config.getDatabaseManager().initPool();
if(config.getDatabaseManager().checkConnection())
log.atInfo().log("Database connected!");
else{
log.atFatal().log("Unable to connect to database.");
System.exit(1);
return;
}
loadCronJob();
new Thread(()->{testRefData();}).start();
while(true);
}
private void testRefData() {
log.atInfo().log("Testing reference data");
ConfigurationManager conf = ConfigurationManager.getInstance();
CorpusDao.Query query = new CorpusDao.QueryBuilder()
.addCrsCode("ECR").addCrsCode("VIC")
.addDescription("croydon").build();
try {
Collection<Corpus> list = conf.getDatabaseManager().getCORPUSDao().executeQuery(query);
log.atDebug().log("{} entries found", list.size());
for(Corpus corpus:list){
log.atDebug().log("Found entry : {}", corpus);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
private void loadCronJob() {
log.atDebug().log("Start loading cron jobs");
try {
scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
if(ConfigurationManager.getInstance().getProperty(Constants.Configuration.ALWAYS_RUN_REF_DATA,"").equals("true")){
log.atInfo().log("Loading Reference data now");
scheduler.scheduleJob(
JobBuilder.newJob(ReferenceDataJob.class).withIdentity("J-OF-"+Constants.CronJob.REFERENCE_DATA).build(),
TriggerBuilder.newTrigger().withIdentity("T-OF-"+Constants.CronJob.REFERENCE_DATA).startAt(DateBuilder.evenSecondDateAfterNow()).build()
);
}
scheduler.scheduleJob(
JobBuilder.newJob(ReferenceDataJob.class).withIdentity("J-CW-"+Constants.CronJob.REFERENCE_DATA).build(),
TriggerBuilder.newTrigger().withIdentity("T-CW-"+Constants.CronJob.REFERENCE_DATA)
.withSchedule(CronScheduleBuilder.cronSchedule("* 10 1 ? * 1")).build()
);
} catch (SchedulerException e) {
log.atFatal().withThrowable(e).log("Unable to create cron jobs");
}
}
}

127
src/main/java/org/leolo/nrdatad/ConfigurationManager.java

@ -0,0 +1,127 @@
package org.leolo.nrdatad;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.leolo.nrdatad.db.DatabaseManager;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.*;
import java.util.function.BiConsumer;
public final class ConfigurationManager {
private static ConfigurationManager instance;
Logger logger = LogManager.getLogger();
Properties prop = new Properties();
private DatabaseManager databaseManager;
public DatabaseManager getDatabaseManager() {
return databaseManager;
}
public void setDatabaseManager(DatabaseManager databaseManager) {
this.databaseManager = databaseManager;
}
public synchronized static ConfigurationManager getInstance(){
if(instance==null){
instance = new ConfigurationManager();
}
return instance;
}
private ConfigurationManager(){
}
public void loadConfiguration(String configPath) throws IOException{
logger.atInfo().log("Loading configuration file {}.", configPath);
try(FileReader reader = new FileReader(configPath)) {
prop.load(reader);
}
logger.atInfo().log("Loaded {} setting(s)", prop.size());
}
public Object setProperty(String key, String value) {
return prop.setProperty(key, value);
}
public String getProperty(String key) {
return prop.getProperty(key);
}
public String getProperty(String key, String defaultValue) {
return prop.getProperty(key, defaultValue);
}
public Enumeration<?> propertyNames() {
return prop.propertyNames();
}
public Set<String> stringPropertyNames() {
return prop.stringPropertyNames();
}
public void list(PrintStream out) {
prop.list(out);
}
public void list(PrintWriter out) {
prop.list(out);
}
public int size() {
return prop.size();
}
public boolean isEmpty() {
return prop.isEmpty();
}
public Enumeration<Object> keys() {
return prop.keys();
}
public Enumeration<Object> elements() {
return prop.elements();
}
public boolean contains(Object value) {
return prop.contains(value);
}
public boolean containsValue(Object value) {
return prop.containsValue(value);
}
public boolean containsKey(Object key) {
return prop.containsKey(key);
}
public Set<Object> keySet() {
return prop.keySet();
}
public Collection<Object> values() {
return prop.values();
}
public Set<Map.Entry<Object, Object>> entrySet() {
return prop.entrySet();
}
protected void clear(){
prop.clear();
}
public Object getOrDefault(Object key, Object defaultValue) {
return prop.getOrDefault(key, defaultValue);
}
public void forEach(BiConsumer<? super Object, ? super Object> action) {
prop.forEach(action);
}
}

23
src/main/java/org/leolo/nrdatad/Constants.java

@ -0,0 +1,23 @@
package org.leolo.nrdatad;
public final class Constants {
public static class Metadata{
public static final String LAST_LTP = "01-last-ltp-time";
}
public static class CronJob{
public static final String REFERENCE_DATA = "refd";
}
public static class Configuration {
public static final String ALWAYS_RUN_LTP = "cron.ltp.always";
public static final String ALWAYS_RUN_REF_DATA = "cron.ref.always";
public static final String NETWORK_RAIL_USER = "network.user";
public static final String NETWORK_RAIL_PASSWORD = "network.pwd";
}
public static class NetworkRailURI{
public static final String CORPUS_URL = "https://datafeeds.networkrail.co.uk/ntrod/SupportingFileAuthenticate?type=CORPUS";
public static final String SMART_URL = "https://datafeeds.networkrail.co.uk/ntrod/SupportingFileAuthenticate?type=SMART";
}
}

102
src/main/java/org/leolo/nrdatad/cron/ReferenceDataJob.java

@ -0,0 +1,102 @@
package org.leolo.nrdatad.cron;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONObject;
import org.leolo.nrdatad.ConfigurationManager;
import org.leolo.nrdatad.Constants;
import org.leolo.nrdatad.db.CorpusDao;
import org.leolo.nrdatad.model.Corpus;
import org.leolo.nrdatad.model.Smart;
import org.leolo.nrdatad.util.HttpUtil;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
public class ReferenceDataJob implements Job {
Logger log = LogManager.getLogger();
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
log.atInfo().log("Load reference data triggered at {}", context.getFireTime());
//There are 2 different kind of reference data. Create 2 thread and deal with them
new Thread(()->{processCORPUS();}).start();
new Thread(()->{processSMART();}).start();
}
private void processSMART() {
ConfigurationManager conf = ConfigurationManager.getInstance();
log.atInfo().log("Loading SMART");
String json = null;
try {
json = HttpUtil.sendHttpRequestForGZipFile(
Constants.NetworkRailURI.SMART_URL,
conf.getProperty(Constants.Configuration.NETWORK_RAIL_USER),
conf.getProperty(Constants.Configuration.NETWORK_RAIL_PASSWORD)
);
} catch (IOException|URISyntaxException e) {
log.atError().withThrowable(e).log("Error when getting CORPUS data");
return;
}
JSONObject rootObj = new JSONObject(json);
JSONArray rootArray = rootObj.getJSONArray("BERTHDATA");
log.atInfo().log("{} entries found", rootArray.length());
Collection<Smart> smarts = new ArrayList<>();
for (int i = 0; i < rootArray.length(); i++) {
JSONObject obj = rootArray.getJSONObject(i);
Smart smart = Smart.parseJSON(obj);
if(!smart.checkEnums()){
log.atInfo().log("Improper SMART record: {}", obj);
continue;
}
smarts.add(smart);
}
try {
conf.getDatabaseManager().getSmartDao().truncateTable();
conf.getDatabaseManager().getSmartDao().addAll(smarts);
} catch (SQLException e) {
log.atError().withThrowable(e).log("Unable to insert records");
}
log.atInfo().log("Done inserting SMART");
}
private void processCORPUS(){
ConfigurationManager conf = ConfigurationManager.getInstance();
log.atInfo().log("Loading CORPUS");
String json = null;
try {
json = HttpUtil.sendHttpRequestForGZipFile(
Constants.NetworkRailURI.CORPUS_URL,
conf.getProperty(Constants.Configuration.NETWORK_RAIL_USER),
conf.getProperty(Constants.Configuration.NETWORK_RAIL_PASSWORD)
);
} catch (IOException|URISyntaxException e) {
log.atError().withThrowable(e).log("Error when getting CORPUS data");
return;
}
JSONObject rootObj = new JSONObject(json);
JSONArray rootArray = rootObj.getJSONArray("TIPLOCDATA");
log.atInfo().log("{} entries found", rootArray.length());
ArrayList<Corpus> corpusList = new ArrayList<>();
for(int i=0;i<rootArray.length();i++){
JSONObject obj = rootArray.getJSONObject(i);
corpusList.add(Corpus.parseJSON(obj));
}
log.atInfo().log("Going to replace the data");
try {
CorpusDao cDao = conf.getDatabaseManager().getCORPUSDao();
cDao.replaceAll(corpusList);
} catch (SQLException e) {
log.atError().withThrowable(e).log("Unable to insert records");
}
log.atInfo().log("Done inserting CORPUS");
}
}

48
src/main/java/org/leolo/nrdatad/db/BaseDao.java

@ -0,0 +1,48 @@
package org.leolo.nrdatad.db;
import org.jetbrains.annotations.Nullable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
public abstract class BaseDao {
private DatabaseManager manager;
public BaseDao(DatabaseManager manager){
this.manager = manager;
}
protected Connection getConnection() throws SQLException{
return manager.getConnection();
}
protected void setString(PreparedStatement stmt, int pos, @Nullable String data) throws SQLException{
if(data==null||data.strip().length()==0){
stmt.setNull(pos, Types.CHAR);
}else{
stmt.setString(pos, data);
}
}
protected void setInt(PreparedStatement stmt, int pos, int val) throws SQLException{
stmt.setInt(pos, val);
}
protected String getQueryParams(int count){
if(count <= 0){
throw new IllegalArgumentException("count must be greater than 0");
}
StringBuilder sb = new StringBuilder();
for(int i=0;i<count;i++){
if(i>0){
sb.append(",");
}
sb.append("?");
}
return sb.toString();
}
}

146
src/main/java/org/leolo/nrdatad/db/CorpusDao.java

@ -0,0 +1,146 @@
package org.leolo.nrdatad.db;
import org.leolo.nrdatad.model.Corpus;
import java.sql.SQLException;
import java.util.*;
public abstract class CorpusDao extends BaseDao{
public CorpusDao(DatabaseManager manager) {
super(manager);
}
public static class QueryBuilder{
private Set<String> stanox = new HashSet<>();
private Set<String> uicCode = new HashSet<>();
private Set<String> crsCode = new HashSet<>();
private Set<String> tiplocCode = new HashSet<>();
private Set<String> nlcCode = new HashSet<>();
private Set<String> description = new HashSet<>();
SearchMode searchMode = SearchMode.MATCH_ALL_GROUP;
public QueryBuilder setSearchMode(SearchMode searchMode) {
this.searchMode = searchMode;
return this;
}
public QueryBuilder addStanox(String stanox){
this.stanox.add(stanox);
return this;
}
public QueryBuilder addUicCode(String uicCode){
this.uicCode.add(uicCode);
return this;
}
public QueryBuilder addCrsCode(String crsCode){
this.crsCode.add(crsCode);
return this;
}
public QueryBuilder addTiplocCode(String tiplocCode){
this.tiplocCode.add(tiplocCode);
return this;
}
public QueryBuilder addNlcCode(String nlcCode){
this.nlcCode.add(nlcCode);
return this;
}
public QueryBuilder addDescription(String description){
this.description.add(description);
return this;
}
public Query build(){
return new Query(stanox, uicCode, crsCode, tiplocCode, nlcCode, description, searchMode);
}
}
public static class Query{
private Set<String> stanox = new HashSet<>();
private Set<String> uicCode = new HashSet<>();
private Set<String> crsCode = new HashSet<>();
private Set<String> tiplocCode = new HashSet<>();
private Set<String> nlcCode = new HashSet<>();
private Set<String> description = new HashSet<>();
SearchMode searchMode = SearchMode.MATCH_ALL_GROUP;
private Query(Set<String> stanox, Set<String> uicCode, Set<String> crsCode, Set<String> tiplocCode, Set<String> nlcCode, Set<String> description, SearchMode searchMode) {
this.stanox = Collections.unmodifiableSet(stanox);
this.uicCode = Collections.unmodifiableSet(uicCode);
this.crsCode = Collections.unmodifiableSet(crsCode);
this.tiplocCode = Collections.unmodifiableSet(tiplocCode);
this.nlcCode = Collections.unmodifiableSet(nlcCode);
this.description = Collections.unmodifiableSet(description);
this.searchMode = searchMode;
}
public Set<String> getStanox() {
return stanox;
}
public Set<String> getUicCode() {
return uicCode;
}
public Set<String> getCrsCode() {
return crsCode;
}
public Set<String> getTiplocCode() {
return tiplocCode;
}
public Set<String> getNlcCode() {
return nlcCode;
}
public Set<String> getDescription() {
return description;
}
public SearchMode getSearchMode() {
return searchMode;
}
}
public abstract Collection<Corpus> executeQuery(Query query) throws SQLException;
public abstract void add(Corpus corpus) throws SQLException;
public void addAll(Collection<Corpus> datas) throws SQLException {
for(Corpus corpus: datas){
add(corpus);
}
}
public abstract void truncateTable() throws SQLException;
public abstract boolean hasNlcCode(String nlcCode) throws SQLException;
public abstract void update(Corpus corpus) throws SQLException;
public void replace(Corpus corpus) throws SQLException{
if(corpus.getNlcCode()==null || !hasNlcCode(corpus.getNlcCode())){
add(corpus);
}else{
update(corpus);
}
}
public void replaceAll(Collection<Corpus> datas) throws SQLException{
for(Corpus corpus: datas){
replace(corpus);
}
}
public abstract Collection<Corpus> searchCORPUSByStanoxCode(String stanoxCode) throws SQLException;
public abstract Collection<Corpus> searchCORPUSByUicCode(String uicCode) throws SQLException;
public abstract Collection<Corpus> searchCORPUSByCrsCode(String crsCode) throws SQLException;
public abstract Collection<Corpus> searchCORPUSByTiplocCode(String tiplocCode) throws SQLException;
public abstract Corpus searchCORPUSByNlcCode(String nlcCode) throws SQLException;
public abstract List<Corpus> searchCORPUSByName(String name) throws SQLException;
public abstract Corpus delete(String nlcCode) throws SQLException;
}

19
src/main/java/org/leolo/nrdatad/db/DatabaseManager.java

@ -0,0 +1,19 @@
package org.leolo.nrdatad.db;
import java.sql.Connection;
import java.sql.SQLException;
public interface DatabaseManager {
public void initPool();
public boolean checkConnection();
public Connection getConnection() throws SQLException;
public MetadataDao getMetadataDao();
public CorpusDao getCORPUSDao();
public SmartDao getSmartDao();
}

42
src/main/java/org/leolo/nrdatad/db/MetadataDao.java

@ -0,0 +1,42 @@
package org.leolo.nrdatad.db;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.leolo.nrdatad.ConfigurationManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Set;
import java.util.function.BiConsumer;
public abstract class MetadataDao extends BaseDao {
Logger log = LogManager.getLogger();
public MetadataDao(DatabaseManager manager){
super(manager);
}
public abstract String getMetadata(String key, String defaultValue) throws SQLException;
public String getMetadata(String key) throws SQLException{
return getMetadata(key, null);
}
public abstract void updateMetadata(String key, @NotNull String value) throws SQLException;
public abstract Set<String> getKeys() throws SQLException;
public abstract void forEach(BiConsumer<String, String> action) throws SQLException;
public boolean containsKey(String key) throws SQLException{
return getKeys().contains(key);
}
public int entryCount() throws SQLException{
return getKeys().size();
}
}

65
src/main/java/org/leolo/nrdatad/db/ParameterStore.java

@ -0,0 +1,65 @@
package org.leolo.nrdatad.db;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class ParameterStore extends ArrayList<String> {
@Override
public int indexOf(Object o) {
return super.indexOf(o)+1;
}
public void addAllObject(@NotNull Collection<?> c){
for(Object obj:c){
add(c.toString());
}
}
public void addObject(Object obj){
add(obj==null?null:obj.toString());
}
@Override
public int lastIndexOf(Object o) {
return super.lastIndexOf(o)+1;
}
@Override
public String get(int index) {
return super.get(index-1);
}
@Override
public String set(int index, String element) {
return super.set(index-1, element);
}
@Override
public void add(int index, String element) {
super.add(index-1, element);
}
@Override
public String remove(int index) {
return super.remove(index-1);
}
@Override
public boolean addAll(int index, Collection<? extends String> c) {
return super.addAll(index-1, c);
}
@Override
protected void removeRange(int fromIndex, int toIndex) {
super.removeRange(fromIndex-1, toIndex-1);
}
@Override
public List<String> subList(int fromIndex, int toIndex) {
return super.subList(fromIndex-1, toIndex-1);
}
}

17
src/main/java/org/leolo/nrdatad/db/SearchMode.java

@ -0,0 +1,17 @@
package org.leolo.nrdatad.db;
public enum SearchMode {
/**
* Indicate all condition must be matched
*/
MATCH_ALL,
/**
* Indicate at least one condition in every group must be matched
*/
MATCH_ALL_GROUP,
/**
* Indicate at least one condition must be matched.
*/
MATCH_ANY;
}

229
src/main/java/org/leolo/nrdatad/db/SmartDao.java

@ -0,0 +1,229 @@
package org.leolo.nrdatad.db;
import org.leolo.nrdatad.model.Corpus;
import org.leolo.nrdatad.model.Smart;
import org.leolo.nrdatad.model.SmartEvent;
import org.leolo.nrdatad.model.SmartStepType;
import org.leolo.nrdatad.util.Range;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public abstract class SmartDao extends BaseDao{
public SmartDao(DatabaseManager manager) {
super(manager);
}
public abstract void add(Smart smart) throws SQLException;
public abstract void truncateTable() throws SQLException;
public void addAll(Collection<Smart> smarts) throws SQLException{
for(Smart smart: smarts){
add(smart);
}
}
public abstract Collection<Smart> searchSmartByBerth(String fromBerth, String toBerth) throws SQLException;
public abstract Collection<Smart> searchFromByBerth(String fromBerth) throws SQLException;
public abstract Collection<Smart> searchToBerth(String toBerth) throws SQLException;
public abstract Collection<Smart> searchSmartByBerthLine(String fromBerth, String toBerth, String fromLine, String toLine) throws SQLException;
public abstract Collection<Smart> searchSmartByFromBerthLine(String fromBerth,String fromLine) throws SQLException;
public abstract Collection<Smart> searchSmartByToBerthLine(String toBerth, String toLine) throws SQLException;
public abstract Collection<Smart> searchSmartByStanox(String stanox) throws SQLException;
public abstract Collection<Smart> executeQuery(Query query) throws SQLException;
public static class QueryBuilder{
private Set<String> td = new HashSet<>();
private Set<String> fromBerth = new HashSet<>();
private Set<String> toBerth = new HashSet<>();
private Set<String> fromLine = new HashSet<>();
private Set<String> toLine = new HashSet<>();
private Set<Range<Integer>> berthOffset = new HashSet<>();
private Set<String> platform = new HashSet<>();
private Set<SmartEvent> event = new HashSet<>();
private Set<String> route = new HashSet<>();
private Set<String> stanox = new HashSet<>();
private Set<String> stationName = new HashSet<>();
private Set<SmartStepType> stepType = new HashSet<>();
private Set<String> comment = new HashSet<>();
private SearchMode searchMode = SearchMode.MATCH_ALL_GROUP;
public QueryBuilder addTd(String td){
this.td.add(td);
return this;
}
public QueryBuilder addFromBerth(String fromBerth){
this.fromBerth.add(fromBerth);
return this;
}
public QueryBuilder addToBerth(String toBerth){
this.toBerth.add(toBerth);
return this;
}
public QueryBuilder addFromLine(String fromLine){
this.fromLine.add(fromLine);
return this;
}
public QueryBuilder addToLine(String toLine){
this.toLine.add(toLine);
return this;
}
public QueryBuilder addBerthOffset(int bound1, int bound2){
this.berthOffset.add(new Range<>(bound1, bound2));
return this;
}
public QueryBuilder addPlatform(String platform){
this.platform.add(platform);
return this;
}
public QueryBuilder addEvent(SmartEvent event){
this.event.add(event);
return this;
}
public QueryBuilder addRoute(String route){
this.route.add(route);
return this;
}
public QueryBuilder addStanox(String stanox){
this.stanox.add(stanox);
return this;
}
public QueryBuilder addStationName(String stationName){
this.stationName.add(stationName);
return this;
}
public QueryBuilder addStepType(SmartStepType stepType){
this.stepType.add(stepType);
return this;
}
public QueryBuilder addComment(String comment){
this.comment.add(comment);
return this;
}
public QueryBuilder setSearchMode(SearchMode searchMode){
this.searchMode=searchMode;
return this;
}
public Query build(){
return new Query(td, fromBerth, toBerth, fromLine, toLine, berthOffset, platform, event, route, stanox, stationName, stepType, comment, searchMode);
}
}
public static class Query{
private Set<String> td;
private Set<String> fromBerth;
private Set<String> toBerth;
private Set<String> fromLine;
private Set<String> toLine;
private Set<Range<Integer>> berthOffset;
private Set<String> platform;
private Set<SmartEvent> event;
private Set<String> route;
private Set<String> stanox;
private Set<String> stationName;
private Set<SmartStepType> stepType;
private Set<String> comment;
private SearchMode searchMode = SearchMode.MATCH_ALL_GROUP;
public Query(Set<String> td, Set<String> fromBerth, Set<String> toBerth, Set<String> fromLine, Set<String> toLine, Set<Range<Integer>> berthOffset, Set<String> platform, Set<SmartEvent> event, Set<String> route, Set<String> stanox, Set<String> stationName, Set<SmartStepType> stepType, Set<String> comment, SearchMode searchMode) {
this.td = Collections.unmodifiableSet(td);
this.fromBerth = Collections.unmodifiableSet(fromBerth);
this.toBerth = Collections.unmodifiableSet(toBerth);
this.fromLine = Collections.unmodifiableSet(fromLine);
this.toLine = Collections.unmodifiableSet(toLine);
this.berthOffset = Collections.unmodifiableSet(berthOffset);
this.platform = Collections.unmodifiableSet(platform);
this.event = Collections.unmodifiableSet(event);
this.route = Collections.unmodifiableSet(route);
this.stanox = Collections.unmodifiableSet(stanox);
this.stationName = Collections.unmodifiableSet(stationName);
this.stepType = Collections.unmodifiableSet(stepType);
this.comment = Collections.unmodifiableSet(comment);
this.searchMode = searchMode;
}
public Set<String> getTd() {
return td;
}
public Set<String> getFromBerth() {
return fromBerth;
}
public Set<String> getToBerth() {
return toBerth;
}
public Set<String> getFromLine() {
return fromLine;
}
public Set<String> getToLine() {
return toLine;
}
public Set<Range<Integer>> getBerthOffset() {
return berthOffset;
}
public Set<String> getPlatform() {
return platform;
}
public Set<SmartEvent> getEvent() {
return event;
}
public Set<String> getRoute() {
return route;
}
public Set<String> getStanox() {
return stanox;
}
public Set<String> getStationName() {
return stationName;
}
public Set<SmartStepType> getStepType() {
return stepType;
}
public Set<String> getComment() {
return comment;
}
public SearchMode getSearchMode() {
return searchMode;
}
}
}

379
src/main/java/org/leolo/nrdatad/db/mariadb/CorpusDao.java

@ -0,0 +1,379 @@
package org.leolo.nrdatad.db.mariadb;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.leolo.nrdatad.db.DatabaseManager;
import org.leolo.nrdatad.db.ParameterStore;
import org.leolo.nrdatad.db.SearchMode;
import org.leolo.nrdatad.model.Corpus;
import java.sql.*;
import java.util.*;
public class CorpusDao extends org.leolo.nrdatad.db.CorpusDao {
Logger log = LogManager.getLogger();
public CorpusDao(DatabaseManager manager) {
super(manager);
}
@Override
public Collection<Corpus> executeQuery(org.leolo.nrdatad.db.CorpusDao.Query query) throws SQLException {
Vector<Corpus> corpuses = new Vector<>();
ParameterStore params = new ParameterStore();
StringBuilder sql = new StringBuilder();
if(query.getSearchMode()== SearchMode.MATCH_ALL_GROUP || query.getSearchMode()==SearchMode.MATCH_ANY){
sql.append("SELECT * FROM corpus WHERE ");
String keyWord;
if(query.getSearchMode() == SearchMode.MATCH_ALL_GROUP){
sql.append("1=1 ");
keyWord = "AND ";
}else{
sql.append("1=0 ");
keyWord = "OR ";
}
if(query.getStanox().size()>0){
sql.append(keyWord).append("stanox IN (")
.append(getQueryParams(query.getStanox().size())).append(") ");
params.addAll(query.getStanox());
}
if(query.getUicCode().size()>0){
sql.append(keyWord).append("uic_code IN (")
.append(getQueryParams(query.getUicCode().size())).append(") ");
params.addAll(query.getUicCode());
}
if(query.getCrsCode().size()>0){
sql.append(keyWord).append("crs_code IN (")
.append(getQueryParams(query.getCrsCode().size())).append(") ");
params.addAll(query.getCrsCode());
}
if(query.getTiplocCode().size()>0){
sql.append(keyWord).append("tiploc_code IN (")
.append(getQueryParams(query.getTiplocCode().size())).append(") ");
params.addAll(query.getTiplocCode());
}
if(query.getNlcCode().size()>0){
sql.append(keyWord).append("nlc_code IN(")
.append(getQueryParams(query.getNlcCode().size())).append(") ");
params.addAll(query.getNlcCode());
}
if(query.getDescription().size()>0){
sql.append(keyWord).append("(");
boolean hasDesc = false;
for(String str:query.getDescription()){
if(hasDesc){
sql.append("OR ");
}
sql.append("(`desc` LIKE ? OR short_desc LIKE ? ) ");
hasDesc = true;
params.add("%"+str+"%");
params.add("%"+str+"%");
}
sql.append(") ");
}
log.atDebug().log("SQL={}",sql);
}else{
log.always().log("Search mode {} is yet to be implemented.", query.getSearchMode());
}
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql.toString())
){
for(int i=1;i<=params.size();i++){
log.atDebug().log("Param {} = {}", i, params.get(i));
setString(pstmt, i, params.get(i));
}
try(ResultSet rs = pstmt.executeQuery()){
while(rs.next()){
corpuses.add(parseCORPUS(rs));
}
}
}
return corpuses;
}
@Override
public void add(@NotNull Corpus corpus) throws SQLException {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"INSERT INTO corpus (stanox, uic_code, crs_code, tiploc_code, nlc_code, `desc`, short_desc) " +
"VALUES (?,?,?,?,?,?,?)")
){
setString(pstmt, 1, corpus.getStanoxCode());
setString(pstmt, 2, corpus.getUicCode());
setString(pstmt, 3, corpus.getCrsCode());
setString(pstmt, 4, corpus.getTiplocCode());
setString(pstmt, 5, corpus.getNlcCode());
setString(pstmt, 6, corpus.getLongDescription());
setString(pstmt, 7, corpus.getShortDescription());
pstmt.executeUpdate();
conn.commit();
}
}
@Override
public void addAll(@NotNull Collection<Corpus> datas) throws SQLException {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"INSERT INTO corpus (stanox, uic_code, crs_code, tiploc_code, nlc_code, `desc`, short_desc) " +
"VALUES (?,?,?,?,?,?,?)")
){
for(Corpus corpus:datas) {
setString(pstmt, 1, corpus.getStanoxCode());
setString(pstmt, 2, corpus.getUicCode());
setString(pstmt, 3, corpus.getCrsCode());
setString(pstmt, 4, corpus.getTiplocCode());
setString(pstmt, 5, corpus.getNlcCode());
setString(pstmt, 6, corpus.getLongDescription());
setString(pstmt, 7, corpus.getShortDescription());
pstmt.addBatch();
}
pstmt.executeBatch();
conn.commit();
}
}
@Override
public void replaceAll(@NotNull Collection<Corpus> datas) throws SQLException {
int totalCount = 0, insertCount = 0, updateCount = 0;
HashSet<String> pendingInsert = new HashSet<>();
try(
Connection conn = getConnection();
PreparedStatement psIns = conn.prepareStatement(
"INSERT INTO corpus (stanox, uic_code, crs_code, tiploc_code, `desc`, short_desc, nlc_code) " +
"VALUES (?,?,?,?,?,?,?)");
PreparedStatement psUpd = conn.prepareStatement(
"UPDATE corpus " +
"SET stanox=?, uic_code=?, crs_code=?, tiploc_code=?, `desc`=?, short_desc=? " +
"WHERE nlc_code = ?"
)
){
for(Corpus corpus:datas){
totalCount++;
Corpus existing = searchCORPUSByNlcCode(corpus.getNlcCode());
PreparedStatement stmt = null;
if(corpus.equals(existing)){
continue;
}else if(existing==null){
if(pendingInsert.contains(corpus.getNlcCode())){
continue;
}
pendingInsert.add(corpus.getNlcCode());
stmt = psIns;
insertCount++;
}else{
stmt = psUpd;
updateCount++;
}
setString(stmt, 1, corpus.getStanoxCode());
setString(stmt, 2, corpus.getUicCode());
setString(stmt, 3, corpus.getCrsCode());
setString(stmt, 4, corpus.getTiplocCode());
setString(stmt, 5, corpus.getLongDescription());
setString(stmt, 6, corpus.getShortDescription());
setString(stmt, 7, corpus.getNlcCode());
stmt.addBatch();
}
if(insertCount>0){
psIns.executeBatch();
log.atInfo().log("Inserted {} CORPUS records", insertCount);
}
if(updateCount>0){
psUpd.executeBatch();
log.atInfo().log("Updated {} CORPUS records", updateCount);
}
if(insertCount==0 && updateCount==0){
log.atInfo().log("CORPUS data already up to date. ");
}else{
conn.commit();
log.atInfo().log("Done committing CORPUS data");
}
}
}
@Override
public void truncateTable() throws SQLException {
try(
Connection conn = getConnection();
Statement stmt = conn.createStatement()
){
stmt.executeQuery("TRUNCATE TABLE corpus");
}
}
@Override
public boolean hasNlcCode(String nlcCode) throws SQLException {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT 1 FROM corpus WHERE nlc_code = ?")
){
pstmt.setString(1, nlcCode);
try(ResultSet rs = pstmt.executeQuery()){
return rs.next();
}
}
}
@Override
public void update(Corpus corpus) throws SQLException {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"UPDATE corpus " +
"SET stanox=?, uic_code=?, crs_code=?, tiploc_code=?, `desc`=?, short_desc=? " +
"WHERE nlc_code = ?"
)
){
setString(pstmt, 1, corpus.getStanoxCode());
setString(pstmt, 2, corpus.getUicCode());
setString(pstmt, 3, corpus.getCrsCode());
setString(pstmt, 4, corpus.getTiplocCode());
setString(pstmt, 5, corpus.getLongDescription());
setString(pstmt, 6, corpus.getShortDescription());
setString(pstmt, 7, corpus.getNlcCode());
pstmt.executeUpdate();
}
}
@Override
public Collection<Corpus> searchCORPUSByStanoxCode(String stanoxCode) throws SQLException {
Collection<Corpus> corpuses = new Vector<>();
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM corpus WHERE stanox = ?")
){
pstmt.setString(1, stanoxCode);
try(ResultSet rs = pstmt.executeQuery()){
while(rs.next()){
corpuses.add(parseCORPUS(rs));
}
}
}
return corpuses;
}
@Override
public Collection<Corpus> searchCORPUSByUicCode(String uicCode) throws SQLException {
Collection<Corpus> corpuses = new Vector<>();
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM corpus WHERE uic_code = ?")
){
pstmt.setString(1, uicCode);
try(ResultSet rs = pstmt.executeQuery()){
while(rs.next()){
corpuses.add(parseCORPUS(rs));
}
}
}
return corpuses;
}
@Override
public Collection<Corpus> searchCORPUSByCrsCode(String crsCode) throws SQLException {
Collection<Corpus> corpuses = new Vector<>();
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM corpus WHERE crs_code = ?")
){
pstmt.setString(1, crsCode);
try(ResultSet rs = pstmt.executeQuery()){
while(rs.next()){
corpuses.add(parseCORPUS(rs));
}
}
}
return corpuses;
}
@Override
public Collection<Corpus> searchCORPUSByTiplocCode(String tiplocCode) throws SQLException {
Collection<Corpus> corpuses = new Vector<>();
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM corpus WHERE tiploc_code = ?")
){
pstmt.setString(1, tiplocCode);
try(ResultSet rs = pstmt.executeQuery()){
while(rs.next()){
corpuses.add(parseCORPUS(rs));
}
}
}
return corpuses;
}
@Override
public Corpus searchCORPUSByNlcCode(String nlcCode) throws SQLException {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM corpus WHERE nlc_code = ?")
){
pstmt.setString(1, nlcCode);
try(ResultSet rs = pstmt.executeQuery()){
if(rs.next()){
return parseCORPUS(rs);
}
}
}
return null;
}
@Override
public List<Corpus> searchCORPUSByName(String name) throws SQLException {
List<Corpus> corpuses = new Vector<>();
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM corpus WHERE " +
"match(`desc`) against (?) OR " +
"match(short_desc) against (?) " +
"ORDER BY match(`desc`) against (?)+match(short_desc) against (?)"
)
){
pstmt.setString(1, name);
pstmt.setString(2, name);
pstmt.setString(3, name);
pstmt.setString(4, name);
try(ResultSet rs = pstmt.executeQuery()){
while(rs.next()){
corpuses.add(parseCORPUS(rs));
}
}
}
return corpuses;
}
private Corpus parseCORPUS(ResultSet rs) throws SQLException{
Corpus corpus = new Corpus();
corpus.setStanoxCode(rs.getString("stanox"));
corpus.setUicCode(rs.getString("uic_code"));
corpus.setCrsCode(rs.getString("crs_code"));
corpus.setTiplocCode(rs.getString("tiploc_code"));
corpus.setNlcCode(rs.getString("nlc_code"));
corpus.setLongDescription(rs.getString("desc"));
corpus.setShortDescription(rs.getString("short_desc"));
return corpus;
}
@Override
public Corpus delete(String nlcCode) throws SQLException {
Corpus deletedEntry = searchCORPUSByNlcCode(nlcCode);
if(deletedEntry!=null){
try(
Connection conn = getConnection();
PreparedStatement stmt = conn.prepareStatement("DELETE FROM corpus WHERE nlc_code = ?")
){
stmt.setString(1, nlcCode);
stmt.executeUpdate();
}
}
return deletedEntry;
}
}

80
src/main/java/org/leolo/nrdatad/db/mariadb/DatabaseManager.java

@ -0,0 +1,80 @@
package org.leolo.nrdatad.db.mariadb;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.leolo.nrdatad.ConfigurationManager;
import org.leolo.nrdatad.db.CorpusDao;
import org.leolo.nrdatad.db.MetadataDao;
import org.leolo.nrdatad.db.SmartDao;
import org.mariadb.jdbc.MariaDbPoolDataSource;
import java.sql.*;
public class DatabaseManager implements org.leolo.nrdatad.db.DatabaseManager{
Logger logger = LogManager.getLogger();
private MariaDbPoolDataSource ds;
@Override
public void initPool() {
logger.atDebug().log("Start initialize the database pool");
ConfigurationManager conf = ConfigurationManager.getInstance();
if(
!conf.containsKey("db.host")||
!conf.containsKey("db.user")||
!conf.containsKey("db.pwd")||
!conf.containsKey("db.name")
) {
logger.atFatal().log("Missing required property");
System.exit(1);
return;
}
String url = "jdbc:mariadb://"+conf.getProperty("db.host")+
":"+conf.getProperty("db.port", "3306")+
"/"+conf.getProperty("db.name");
logger.atDebug().log("URL={}",url);
try {
ds = new MariaDbPoolDataSource(url);
ds.setMinPoolSize(1);
ds.setMaxPoolSize(Integer.parseInt(conf.getOrDefault("db.poolsize", "20").toString()));
ds.setUser(conf.getProperty("db.user").toString());
ds.setPassword(conf.getProperty("db.pwd").toString());
} catch (SQLException e) {
logger.atFatal().withThrowable(e).log("Cannot connect to DB");
System.exit(-2);
}
}
@Override
public boolean checkConnection() {
try(
Connection conn = ds.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT 1")
){
return rs.next();
}catch(SQLException e){
return false;
}
}
@Override
public Connection getConnection() throws SQLException{
Connection conn = ds.getConnection();
conn.setAutoCommit(false);
return conn;
}
@Override
public MetadataDao getMetadataDao() {
return new org.leolo.nrdatad.db.mariadb.MetadataDao(this);
}
@Override
public CorpusDao getCORPUSDao() {
return new org.leolo.nrdatad.db.mariadb.CorpusDao(this);
}
@Override
public SmartDao getSmartDao() {
return new org.leolo.nrdatad.db.mariadb.SmartDao(this);
}
}

116
src/main/java/org/leolo/nrdatad/db/mariadb/MetadataDao.java

@ -0,0 +1,116 @@
package org.leolo.nrdatad.db.mariadb;
import org.jetbrains.annotations.NotNull;
import java.sql.*;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.BiConsumer;
public class MetadataDao extends org.leolo.nrdatad.db.MetadataDao {
private static Object SYNC_TOKEN = new Object();
public MetadataDao(DatabaseManager manager){
super(manager);
}
@Override
public String getMetadata(String key, String defaultValue) throws SQLException {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT value FROM metadata WHERE `key` = ?")
){
pstmt.setString(1, key);
try(ResultSet rs = pstmt.executeQuery()){
if(rs.next()){
return rs.getString(1);
}
}
}
return defaultValue;
}
@Override
public void updateMetadata(@NotNull String key, @NotNull String value) throws SQLException {
synchronized (SYNC_TOKEN) {
if (containsKey(key)) {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("UPDATE metadata SET value = ? WHERE `key` = ?")
){
pstmt.setString(1, value);
pstmt.setString(2, key);
pstmt.executeUpdate();
}
} else {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO metadata (`key`, value) VALUES (?,?)")
){
pstmt.setString(1, key);
pstmt.setString(2, value);
pstmt.executeUpdate();
}
}
}
}
@Override
public Set<String> getKeys() throws SQLException {
HashSet<String> set = new HashSet<>();
try(
Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT `key` FROM metadata")
){
while(rs.next()){
set.add(rs.getString(1));
}
}
return set;
}
@Override
public void forEach(BiConsumer<String, String> action) throws SQLException {
TreeMap<String, String> map = new TreeMap<>();
try(
Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT `key`, value FROM metadata")
){
while(rs.next()){
map.put(rs.getString(1), rs.getString(2));
}
}
map.forEach(action);
}
@Override
public boolean containsKey(String key) throws SQLException {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT 1 FROM metadata WHERE `key` = ?")
){
pstmt.setString(1, key);
try(ResultSet rs = pstmt.executeQuery()){
return rs.next();
}
}
}
@Override
public int entryCount() throws SQLException {
try(
Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT COUNT(1) FROM metadata")
){
rs.next();
return rs.getInt(1);
}
}
}

322
src/main/java/org/leolo/nrdatad/db/mariadb/SmartDao.java

@ -0,0 +1,322 @@
package org.leolo.nrdatad.db.mariadb;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.leolo.nrdatad.db.DatabaseManager;
import org.leolo.nrdatad.db.ParameterStore;
import org.leolo.nrdatad.db.SearchMode;
import org.leolo.nrdatad.model.Smart;
import org.leolo.nrdatad.model.SmartEvent;
import org.leolo.nrdatad.model.SmartStepType;
import org.leolo.nrdatad.util.Range;
import java.sql.*;
import java.util.Collection;
import java.util.Vector;
public class SmartDao extends org.leolo.nrdatad.db.SmartDao {
Logger log = LogManager.getLogger();
public SmartDao(DatabaseManager manager) {
super(manager);
}
@Override
public void add(Smart smart) throws SQLException {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"INSERT INTO smart (" +
"td, from_berth, to_berth, from_line, to_line, breth_offset, platform, event, route, " +
"stanox, station_name, step_type, comment" +
") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)")
){
setString(pstmt, 1, smart.getTd());
setString(pstmt, 2, smart.getFromBerth());
setString(pstmt, 3, smart.getToBerth());
setString(pstmt, 4, smart.getFromLine());
setString(pstmt, 5, smart.getToLine());
setInt (pstmt, 6, smart.getBerthOffset());
setString(pstmt, 7, smart.getPlatform());
setString(pstmt, 8, smart.getEvent().getCode());
setString(pstmt, 9, smart.getRoute());
setString(pstmt, 10, smart.getStanox());
setString(pstmt, 11, smart.getStationName());
setString(pstmt, 12, smart.getStepType().getCode());
setString(pstmt, 13, smart.getComment());
pstmt.executeUpdate();
conn.commit();
}
}
@Override
public void addAll(Collection<Smart> smarts) throws SQLException {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"INSERT INTO smart (" +
"td, from_berth, to_berth, from_line, to_line, breth_offset, platform, event, route, " +
"stanox, station_name, step_type, comment" +
") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)")
){
for(Smart smart:smarts){
setString(pstmt, 1, smart.getTd());
setString(pstmt, 2, smart.getFromBerth());
setString(pstmt, 3, smart.getToBerth());
setString(pstmt, 4, smart.getFromLine());
setString(pstmt, 5, smart.getToLine());
setInt (pstmt, 6, smart.getBerthOffset());
setString(pstmt, 7, smart.getPlatform());
setString(pstmt, 8, smart.getEvent().getCode());
setString(pstmt, 9, smart.getRoute());
setString(pstmt, 10, smart.getStanox());
setString(pstmt, 11, smart.getStationName());
setString(pstmt, 12, smart.getStepType().getCode());
setString(pstmt, 13, smart.getComment());
pstmt.addBatch();
}
pstmt.executeBatch();
conn.commit();
}
}
@Override
public void truncateTable() throws SQLException {
try(
Connection conn = getConnection();
Statement stmt = conn.createStatement()
){
stmt.executeUpdate("TRUNCATE TABLE smart");
}
}
private Smart parseResultSet(ResultSet rs) throws SQLException{
Smart smart = new Smart();
smart.setSmartId(rs.getInt("smart_id"));
smart.setTd(rs.getString("td"));
smart.setFromBerth(rs.getString("from_berth"));
smart.setToBerth(rs.getString("to_berth"));
smart.setFromLine(rs.getString("from_line"));
smart.setToLine(rs.getString("to_line"));
smart.setBerthOffset(rs.getInt("berth_offset"));
smart.setPlatform(rs.getString("platform"));
smart.setEvent(SmartEvent.parseCode(rs.getString("event")));
smart.setRoute(rs.getString("route"));
smart.setStanox(rs.getString("stanox"));
smart.setStationName(rs.getString("station_name"));
smart.setStepType(SmartStepType.parseCode(rs.getString("step_type")));
smart.setComment(rs.getString("comment"));
return smart;
}
@Override
public Collection<Smart> searchSmartByBerth(String fromBerth, String toBerth) throws SQLException {
Vector<Smart> vector = new Vector<>();
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM smart WHERE from_berth = ? AND to_berth = ?");
){
pstmt.setString(1, fromBerth);
pstmt.setString(2, toBerth);
try(ResultSet rs = pstmt.executeQuery()){
vector.add(parseResultSet(rs));
}
}
return vector;
}
@Override
public Collection<Smart> searchFromByBerth(String fromBerth) throws SQLException {
Vector<Smart> vector = new Vector<>();
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM smart WHERE from_berth =?");
){
pstmt.setString(1, fromBerth);
try(ResultSet rs = pstmt.executeQuery()){
vector.add(parseResultSet(rs));
}
}
return vector;
}
@Override
public Collection<Smart> searchToBerth(String toBerth) throws SQLException {Vector<Smart> vector = new Vector<>();
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM smart WHERE to_berth = ?");
){
pstmt.setString(1, toBerth);
try(ResultSet rs = pstmt.executeQuery()){
vector.add(parseResultSet(rs));
}
}
return vector;
}
@Override
public Collection<Smart> searchSmartByBerthLine(String fromBerth, String toBerth, String fromLine, String toLine) throws SQLException {
Vector<Smart> vector = new Vector<>();
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM smart WHERE from_berth = ? AND to_berth = ? AND from_line = ? AND to_line = ?");
){
pstmt.setString(1, fromBerth);
pstmt.setString(2, toBerth);
pstmt.setString(3, fromLine);
pstmt.setString(4, toLine);
try(ResultSet rs = pstmt.executeQuery()){
vector.add(parseResultSet(rs));
}
}
return vector;
}
@Override
public Collection<Smart> searchSmartByFromBerthLine(String fromBerth, String fromLine) throws SQLException {
Vector<Smart> vector = new Vector<>();
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM smart WHERE from_berth = ? AND to_berth = ? AND from_line = ? AND to_line = ?");
){
pstmt.setString(1, fromBerth);
pstmt.setString(2, fromLine);
try(ResultSet rs = pstmt.executeQuery()){
vector.add(parseResultSet(rs));
}
}
return vector;
}
@Override
public Collection<Smart> searchSmartByToBerthLine(String toBerth, String toLine) throws SQLException {
Vector<Smart> vector = new Vector<>();
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM smart WHERE from_berth = ? AND to_berth = ? AND from_line = ? AND to_line = ?");
){
pstmt.setString(1, toBerth);
pstmt.setString(2, toLine);
try(ResultSet rs = pstmt.executeQuery()){
vector.add(parseResultSet(rs));
}
}
return vector;
}
@Override
public Collection<Smart> searchSmartByStanox(String stanox) throws SQLException {Vector<Smart> vector = new Vector<>();
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM smart WHERE stanox = ?");
){
pstmt.setString(1, stanox);
try(ResultSet rs = pstmt.executeQuery()){
vector.add(parseResultSet(rs));
}
}
return vector;
}
@Override
public Collection<Smart> executeQuery(Query query) throws SQLException {
Vector<Smart> smarts = new Vector<>();
ParameterStore ps = new ParameterStore();
StringBuilder sql = new StringBuilder();
if(query.getSearchMode()== SearchMode.MATCH_ALL_GROUP || query.getSearchMode()==SearchMode.MATCH_ANY){
sql.append("SELECT * FROM smart WHERE ");
String keyWord;
if(query.getSearchMode() == SearchMode.MATCH_ALL_GROUP){
sql.append("1=1 ");
keyWord = "AND ";
}else{
sql.append("1=0 ");
keyWord = "OR ";
}
if(query.getTd().size()>0){
sql.append(keyWord).append("td IN (").append(getQueryParams(query.getTd().size())).append(") ");
ps.addAll(query.getTd());
}
if(query.getFromBerth().size()>0){
sql.append(keyWord).append("from_berth IN(").append(getQueryParams(query.getFromBerth().size())).append(") ");
ps.addAll(query.getFromBerth());
}
if(query.getToBerth().size()>0){
sql.append(keyWord).append("to_berth IN(").append(getQueryParams(query.getToBerth().size())).append(") ");
ps.addAll(query.getToBerth());
}
if(query.getFromLine().size()>0){
sql.append(keyWord).append("from_line IN(").append(getQueryParams(query.getFromLine().size())).append(") ");
ps.addAll(query.getFromLine());
}
if (query.getToLine().size()>0){
sql.append(keyWord).append("to_line (").append(getQueryParams(query.getToLine().size())).append(") ");
ps.addAll(query.getToLine());
}
if (query.getBerthOffset().size()>0){
sql.append(keyWord).append("(1=0 ");
for(Range<Integer> range: query.getBerthOffset()){
sql.append("OR (berth_offset BETWEEN ? AND ?) ");
ps.addObject(range.getLowerBound());
ps.addObject(range.getUpperBound());
}
sql.append(") ");
}
if(query.getPlatform().size()>0){
sql.append(keyWord).append("platform IN(").append(getQueryParams(query.getPlatform().size())).append(") ");
ps.addAll(query.getPlatform());
}
if(query.getEvent().size()>0){
sql.append(keyWord).append("event IN(").append(getQueryParams(query.getEvent().size())).append(") ");
ps.addAllObject(query.getEvent());
}
if(query.getRoute().size()>0){
sql.append(keyWord).append("route IN(").append(getQueryParams(query.getRoute().size())).append(") ");
ps.addAll(query.getRoute());
}
if(query.getStanox().size()>0){
sql.append(keyWord).append("stanox IN(").append(getQueryParams(query.getStanox().size())).append(") ");
ps.addAll(query.getStanox());
}
if(query.getStationName().size()>0){
sql.append(keyWord).append("(1=0 ");
for(String stationName: query.getStationName()){
sql.append("OR station_name LIKE ? ");
ps.add("%"+stationName+"%");
}
sql.append(") ");
}
if(query.getStepType().size()>0){
sql.append(keyWord).append("step_type IN(").append(getQueryParams(query.getStepType().size())).append(") ");
ps.addAllObject(query.getStepType());
}
if(query.getComment().size()>0){
sql.append(keyWord).append("(1=0 ");
for(String comment: query.getComment()){
sql.append("OR comment LIKE ? ");
ps.add("%"+comment+"%");
}
sql.append(") ");
}
}
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql.toString())
){
for(int i=1;i<=ps.size();i++){
log.atDebug().log("Param {} = {}", i, ps.get(i));
setString(pstmt, i, ps.get(i));
}
try(ResultSet rs = pstmt.executeQuery()){
while(rs.next()){
smarts.add(parseResultSet(rs));
}
}
}
return smarts;
}
}

115
src/main/java/org/leolo/nrdatad/model/Corpus.java

@ -0,0 +1,115 @@
package org.leolo.nrdatad.model;
import org.json.JSONObject;
import java.util.Objects;
public class Corpus {
private String stanoxCode;
private String uicCode;
private String crsCode;
private String tiplocCode;
private String nlcCode;
private String longDescription;
private String shortDescription;
public String getStanoxCode() {
return stanoxCode;
}
public void setStanoxCode(String stanoxCode) {
this.stanoxCode = stanoxCode;
}
public String getUicCode() {
return uicCode;
}
public void setUicCode(String uicCode) {
this.uicCode = uicCode;
}
public String getCrsCode() {
return crsCode;
}
public void setCrsCode(String crsCode) {
this.crsCode = crsCode;
}
public String getTiplocCode() {
return tiplocCode;
}
public void setTiplocCode(String tiplocCode) {
this.tiplocCode = tiplocCode;
}
public String getNlcCode() {
return nlcCode;
}
public void setNlcCode(String nlcCode) {
this.nlcCode = nlcCode;
}
public String getLongDescription() {
return longDescription;
}
public void setLongDescription(String longDescription) {
this.longDescription = longDescription;
}
public String getShortDescription() {
return shortDescription;
}
public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Corpus corpus = (Corpus) o;
return Objects.equals(stanoxCode, corpus.stanoxCode) && Objects.equals(uicCode, corpus.uicCode) && Objects.equals(crsCode, corpus.crsCode) && Objects.equals(tiplocCode, corpus.tiplocCode) && Objects.equals(nlcCode, corpus.nlcCode) && Objects.equals(longDescription, corpus.longDescription) && Objects.equals(shortDescription, corpus.shortDescription);
}
@Override
public int hashCode() {
return Objects.hash(stanoxCode, uicCode, crsCode, tiplocCode, nlcCode, longDescription, shortDescription);
}
@Override
public String toString() {
return "CORPUS{" +
"stanoxCode='" + stanoxCode + '\'' +
", uicCode='" + uicCode + '\'' +
", crsCode='" + crsCode + '\'' +
", tiplocCode='" + tiplocCode + '\'' +
", nlcCode='" + nlcCode + '\'' +
", longDescription='" + longDescription + '\'' +
", shortDescription='" + shortDescription + '\'' +
'}';
}
public static Corpus parseJSON(JSONObject obj){
Corpus corpus = new Corpus();
corpus.setStanoxCode(obj.optString("STANOX"));
corpus.setUicCode(obj.optString("UIC"));
corpus.setCrsCode(obj.optString("3ALPHA"));
corpus.setTiplocCode(obj.optString("TIPLOC"));
corpus.setNlcCode(obj.optString("NLC"));
corpus.setLongDescription(obj.optString("NLCDESC"));
corpus.setShortDescription(obj.optString("NLCDESC16"));
return corpus;
}
public static Corpus parseJSON(String json){
return parseJSON(new JSONObject(json));
}
}

180
src/main/java/org/leolo/nrdatad/model/Smart.java

@ -0,0 +1,180 @@
package org.leolo.nrdatad.model;
import org.json.JSONObject;
import org.leolo.nrdatad.util.JSONUtil;
public class Smart {
private int smartId;
private String td;
private String fromBerth;
private String toBerth;
private String fromLine;
private String toLine;
private int berthOffset;
private String platform;
private SmartEvent event;
private String route;
private String stanox;
private String stationName;
private SmartStepType stepType;
private String comment;
public int getSmartId() {
return smartId;
}
public void setSmartId(int smartId) {
this.smartId = smartId;
}
public String getTd() {
return td;
}
public void setTd(String td) {
this.td = td;
}
public String getFromBerth() {
return fromBerth;
}
public void setFromBerth(String fromBerth) {
this.fromBerth = fromBerth;
}
public String getToBerth() {
return toBerth;
}
public void setToBerth(String toBerth) {
this.toBerth = toBerth;
}
public String getFromLine() {
return fromLine;
}
public void setFromLine(String fromLine) {
this.fromLine = fromLine;
}
public String getToLine() {
return toLine;
}
public void setToLine(String toLine) {
this.toLine = toLine;
}
public int getBerthOffset() {
return berthOffset;
}
public void setBerthOffset(int berthOffset) {
this.berthOffset = berthOffset;
}
public String getPlatform() {
return platform;
}
public void setPlatform(String platform) {
this.platform = platform;
}
public SmartEvent getEvent() {
return event;
}
public void setEvent(SmartEvent event) {
this.event = event;
}
public String getRoute() {
return route;
}
public void setRoute(String route) {
this.route = route;
}
public String getStanox() {
return stanox;
}
public void setStanox(String stanox) {
this.stanox = stanox;
}
public String getStationName() {
return stationName;
}
public void setStationName(String stationName) {
this.stationName = stationName;
}
public SmartStepType getStepType() {
return stepType;
}
public void setStepType(SmartStepType stepType) {
this.stepType = stepType;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public static Smart parseJSON(String json){
return parseJSON(new JSONObject(json));
}
public static Smart parseJSON(JSONObject obj) {
Smart smart = new Smart();
smart.td = obj.optString("TD");
smart.fromBerth = obj.optString("FROMBERTH");
smart.toBerth = obj.optString("TOBERTH");
smart.fromLine = obj.optString("FROMLINE");
smart.toLine = obj.optString("TOLINE");
smart.berthOffset = JSONUtil.parseInt(obj.optString("BERTHOFFSET"));
smart.platform = obj.optString("PLATFORM");
smart.event = SmartEvent.parseCode(obj.optString("EVENT"));
smart.route = obj.optString("ROUTE");
smart.stanox = obj.optString("STANOX");
smart.stationName = obj.optString("STANME");
smart.stepType = SmartStepType.parseCode(obj.optString("STEPTYPE"));
smart.comment = obj.optString("COMMENT");
return smart;
}
public boolean checkEnums(){
return event!=null && stepType!=null;
}
@Override
public String toString() {
return "Smart{" +
"smartId=" + smartId +
", td='" + td + '\'' +
", fromBerth='" + fromBerth + '\'' +
", toBerth='" + toBerth + '\'' +
", fromLine='" + fromLine + '\'' +
", toLine='" + toLine + '\'' +
", berthOffset=" + berthOffset +
", platform='" + platform + '\'' +
", event=" + event +
", route='" + route + '\'' +
", stanox='" + stanox + '\'' +
", stationName='" + stationName + '\'' +
", stepType=" + stepType +
", comment='" + comment + '\'' +
'}';
}
}

31
src/main/java/org/leolo/nrdatad/model/SmartEvent.java

@ -0,0 +1,31 @@
package org.leolo.nrdatad.model;
import org.jetbrains.annotations.NotNull;
public enum SmartEvent {
ARRIVE_UP ("A"),
DEPART_UP ("B"),
ARRIVE_DOWN("C"),
DEPART_DOWN("D");
private String code;
private SmartEvent(String code){
this.code = code;
}
public String getCode() {
return code;
}
public static SmartEvent parseCode(@NotNull String code){
for(SmartEvent se: SmartEvent.values()){
if(code.equalsIgnoreCase(se.code)){
return se;
}
}
return null;
}
}

63
src/main/java/org/leolo/nrdatad/model/SmartStepType.java

@ -0,0 +1,63 @@
package org.leolo.nrdatad.model;
import org.jetbrains.annotations.NotNull;
public enum SmartStepType {
/**
* This is a move between directly adjacent berths, and is the preferred type of movement. The time reported to
* TRUST is the time that the train enters the 'to' berth.
*/
BETWEEN("B"),
/**
* This is used to record a time for a train going in either direction (up or down) from the specified berth to any
* other berth. The time reported to TRUST is the time that the train leaves the 'from' berth.
*/
FROM("F"),
/**
* This is the opposite of the 'F' step type. It is used to record a time for a train from any berth to the
* specified berth. The time reported to TRUST is the time that the train enters the 'to' berth.
*/
TO("T"),
/**
* This is used to specify the route a train is taking, usually when departing a station or junction.
*
* For example, if a 'D' move is specified as 0101 to 0407, and a train moves between berths 0101, 0203, 0305 and
* 0407, the move will be reported for the time the train left the first berth.
*/
INTERMEDIATE_FIRST("D"),
/**
* This is used to report on a movement where the only indication is a cancel message. For example, when a train
* leaves Network Rail infrastructure and moves in to a siding or area not covered by a train describer, the only
* message that will be received is a Clearout (CB) message.
*/
CLEAROUT("C"),
/**
* This is the opposite of the 'C' step type. It is used to report on a movement where the only indication is
* an interpose message. For example, when a train arrives on Network Rail infrastructure from a siding. The time
* reported to TRUST is the time that the interpose happened.
*/
INTERPOSE("I"),
/**
* This is similar to the 'D' move, but usually used for arrivals. The time reported to TRUST is the time the last
* berth step was made.
*/
INTERMEDIATE("E");
private String code;
private SmartStepType(String code){
this.code = code;
}
public String getCode() {
return code;
}
public static SmartStepType parseCode(@NotNull String code){
for(SmartStepType sst: SmartStepType.values()){
if(code.equalsIgnoreCase(sst.code))
return sst;
}
return null;
}
}

63
src/main/java/org/leolo/nrdatad/util/HttpUtil.java

@ -0,0 +1,63 @@
package org.leolo.nrdatad.util;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.leolo.nrdatad.ConfigurationManager;
import org.leolo.nrdatad.Constants;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Base64;
import java.util.zip.GZIPInputStream;
public class HttpUtil {
Logger log = LogManager.getLogger();
public static String sendHttpRequest(URL url, String userName, String password) throws IOException {
URLConnection conn = url.openConnection();
String userpwd = userName+":"+password;
conn.addRequestProperty("Authorization", "Basic "+ Base64.getEncoder().encodeToString(userpwd.getBytes()));
conn.connect();
StringBuilder sb = new StringBuilder();
try(BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()))){
while(true){
String line = br.readLine();
if(line == null) break;
sb.append(line).append("\n");
}
}
return sb.toString();
}
public static String sendHttpRequest(String url, String userName, String password) throws IOException, URISyntaxException {
return sendHttpRequest(new URL(url), userName, password);
}
public static String sendHttpRequestForGZipFile(URL url, String userName, String password) throws IOException {
URLConnection conn = url.openConnection();
String userpwd = userName+":"+password;
conn.addRequestProperty("Authorization", "Basic "+ Base64.getEncoder().encodeToString(userpwd.getBytes()));
conn.connect();
StringBuilder sb = new StringBuilder();
try(
GZIPInputStream gis = new GZIPInputStream(conn.getInputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(gis))
){
while(true){
String line = br.readLine();
if(line == null) break;
sb.append(line).append("\n");
}
}
return sb.toString();
}
public static String sendHttpRequestForGZipFile(String url, String userName, String password) throws IOException, URISyntaxException {
return sendHttpRequestForGZipFile(new URL(url), userName, password);
}
}

17
src/main/java/org/leolo/nrdatad/util/JSONUtil.java

@ -0,0 +1,17 @@
package org.leolo.nrdatad.util;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class JSONUtil {
static Logger log = LogManager.getLogger();
public static int parseInt(String val){
if (val.startsWith("+")) {
return Integer.parseInt(val.substring(1));
}
return Integer.parseInt(val);
}
}

25
src/main/java/org/leolo/nrdatad/util/Range.java

@ -0,0 +1,25 @@
package org.leolo.nrdatad.util;
public class Range<E extends Comparable> {
private E lowerBound;
private E upperBound;
public Range(E bound1, E bound2){
if(bound1.compareTo(bound2)==-1){
lowerBound = bound1;
upperBound = bound2;
}else{
lowerBound = bound2;
upperBound = bound1;
}
}
public E getLowerBound() {
return lowerBound;
}
public E getUpperBound() {
return upperBound;
}
}

22
src/main/resources/log4j2.xml

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<File name="RIlog" fileName="ri_log">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</File>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
<Logger name="org.leolo.nrdd">
<AppenderRef ref="Console" />
<AppenderRef ref="RIlog" />
</Logger>
</Loggers>
</Configuration>

5
src/test/java/org/leolo/AppTest.java → src/test/java/org/leolo/nrdatad/AppTest.java

@ -1,4 +1,4 @@
package org.leolo;
package org.leolo.nrdatad;
import static org.junit.Assert.assertTrue;
@ -7,8 +7,7 @@ import org.junit.Test;
/**
* Unit test for simple App.
*/
public class AppTest
{
public class AppTest {
/**
* Rigorous Test :-)
*/

92
src/test/java/org/leolo/nrdatad/ConfigurationTest.java

@ -0,0 +1,92 @@
package org.leolo.nrdatad;
import org.apache.logging.log4j.LogBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.util.Random;
import static org.junit.Assert.*;
public class ConfigurationTest {
public static final char[] randomChars = "1234567890qwertyuiopasdfghjklzxcvbnm".toCharArray();
private static Logger log = LogManager.getLogger();
private static String fileName;
@Before public void setUpClass(){
int round = 0;
while(true) {
fileName = "test-"+getRandomFileName()+".tmp";
log.always().log("File name is {}", fileName);
if(!new File(fileName).exists()){
break;
}
if(++round>48){
assertTrue("Cannot get a file name", false);
}
}
}
private static String getRandomFileName(){
StringBuilder sb = new StringBuilder();
Random r = new Random();
for(int i=0;i<16;i++){
sb.append(randomChars[r.nextInt(randomChars.length)]);
}
return sb.toString();
}
@Test public void basicLoad() throws Exception{
assertEquals("Dirty configs", 0, ConfigurationManager.getInstance().size());
//Step 1: Create a simple one
try(PrintWriter out = new PrintWriter(new File(fileName))){
out.println("key1=value1");
out.println("key2=value2");
out.println("key3=value3");
out.println("key4=value4");
out.println("#key5=value5");
}catch(IOException e){
log.always().withThrowable(e).log("Unable to test");
assert false;
}
ConfigurationManager.getInstance().loadConfiguration(fileName);
assertEquals("Config key count mismatch", 4, ConfigurationManager.getInstance().size());
assertEquals("Config key count mismatch", "value1", ConfigurationManager.getInstance().getProperty("key1"));
assertEquals("Config key count mismatch", "value3", ConfigurationManager.getInstance().getProperty("key3"));
assertEquals("Config key count mismatch", "value4", ConfigurationManager.getInstance().getProperty("key4"));
assertEquals("Config key count mismatch", "value2", ConfigurationManager.getInstance().getProperty("key2"));
assertEquals("Config key count mismatch", null, ConfigurationManager.getInstance().getProperty("key5"));
}
@Test public void notExistFile(){
assertEquals("Dirty configs", 0, ConfigurationManager.getInstance().size());
try {
ConfigurationManager.getInstance().loadConfiguration(fileName);
}catch(IOException e){
return;
}
assertFalse("Exception not thrown", true);
}
@After public void cleanUpEach(){
try {
Files.deleteIfExists(new File(fileName).toPath());
log.atInfo().log("Removed file {}", fileName);
} catch (IOException e) {
log.always().withThrowable(e).log("Unable to remove file");
}
ConfigurationManager.getInstance().clear();
}
@AfterClass public static void cleanup(){
new File(fileName).deleteOnExit();
}
}

270
src/test/java/org/leolo/nrdatad/ReferenceDataParserTest.java

@ -0,0 +1,270 @@
package org.leolo.nrdatad;
import org.json.JSONObject;
import org.junit.Test;
import org.leolo.nrdatad.model.Corpus;
import org.leolo.nrdatad.model.Smart;
import org.leolo.nrdatad.model.SmartEvent;
import org.leolo.nrdatad.model.SmartStepType;
import static org.junit.Assert.*;
public class ReferenceDataParserTest {
@Test
public void testCorpusNormalCase1(){
String json = "{\"NLC\":\"535500\",\"STANOX\":\"87701\",\"TIPLOC\":\"ECROYDN\",\"3ALPHA\":\"ECR\",\"UIC\":\"53550\",\"NLCDESC\":\"EAST CROYDON\",\"NLCDESC16\":\"\"}";
Corpus corpus = Corpus.parseJSON(json);
assertEquals("535500", corpus.getNlcCode());
assertEquals("87701", corpus.getStanoxCode());
assertEquals("ECROYDN", corpus.getTiplocCode());
assertEquals("ECR", corpus.getCrsCode());
assertEquals("53550", corpus.getUicCode());
assertEquals("EAST CROYDON", corpus.getLongDescription());
}
@Test
public void testCorpusNormalCase2(){
String json = "{\"NLC\":\"535500\",\"STANOX\":\"87701\",\"TIPLOC\":\"ECROYDN\",\"3ALPHA\":\"ECR\",\"UIC\":\"53550\",\"NLCDESC\":\"EAST CROYDON\",\"NLCDESC16\":\"\"}";
Corpus corpus = Corpus.parseJSON(new JSONObject(json));
assertEquals("535500", corpus.getNlcCode());
assertEquals("87701", corpus.getStanoxCode());
assertEquals("ECROYDN", corpus.getTiplocCode());
assertEquals("ECR", corpus.getCrsCode());
assertEquals("53550", corpus.getUicCode());
assertEquals("EAST CROYDON", corpus.getLongDescription());
}
@Test
public void testSmartNormalCase1(){
String json = "{\"STEPTYPE\":\"B\",\"FROMBERTH\":\"7910\",\"TOBERTH\":\"7904\",\"STANOX\":\"01125\",\"EVENT\":\"A\",\"PLATFORM\":\"1\"," +
"\"TOLINE\":\"\",\"BERTHOFFSET\":\"+59\",\"ROUTE\":\"\",\"FROMLINE\":\"\",\"TD\":\"IH\",\"COMMENT\":\"02/12/2018\",\"STANME\":\"NAIRN\"}";
Smart smart = Smart.parseJSON(json);
assertEquals(SmartStepType.BETWEEN, smart.getStepType());
assertEquals("7910", smart.getFromBerth());
assertEquals("7904", smart.getToBerth());
assertEquals("01125", smart.getStanox());
assertEquals(SmartEvent.ARRIVE_UP, smart.getEvent());
assertEquals("1", smart.getPlatform());
assertEquals("", smart.getToLine());
assertEquals(59, smart.getBerthOffset());
assertEquals("", smart.getRoute());
assertEquals("", smart.getFromLine());
assertEquals("IH", smart.getTd());
assertEquals("02/12/2018", smart.getComment());
assertEquals("NAIRN", smart.getStationName());
}
@Test
public void testSmartInvalidEnumVal1(){
String json = "{\"STEPTYPE\":\"B\",\"FROMBERTH\":\"7910\",\"TOBERTH\":\"7904\",\"STANOX\":\"01125\",\"EVENT\":\"Z\",\"PLATFORM\":\"1\"," +
"\"TOLINE\":\"\",\"BERTHOFFSET\":\"+59\",\"ROUTE\":\"\",\"FROMLINE\":\"\",\"TD\":\"IH\",\"COMMENT\":\"02/12/2018\",\"STANME\":\"NAIRN\"}";
Smart smart = Smart.parseJSON(json);
assertEquals(SmartStepType.BETWEEN, smart.getStepType());
assertEquals("7910", smart.getFromBerth());
assertEquals("7904", smart.getToBerth());
assertEquals("01125", smart.getStanox());
assertNull(smart.getEvent());
assertEquals("1", smart.getPlatform());
assertEquals("", smart.getToLine());
assertEquals(59, smart.getBerthOffset());
assertEquals("", smart.getRoute());
assertEquals("", smart.getFromLine());
assertEquals("IH", smart.getTd());
assertEquals("02/12/2018", smart.getComment());
assertEquals("NAIRN", smart.getStationName());
}
@Test
public void testSmartNormalCase2(){
String json = "{\"STEPTYPE\":\"B\",\"FROMBERTH\":\"7910\",\"TOBERTH\":\"7904\",\"STANOX\":\"01125\",\"EVENT\":\"A\",\"PLATFORM\":\"1\"," +
"\"TOLINE\":\"\",\"BERTHOFFSET\":\"+59\",\"ROUTE\":\"\",\"FROMLINE\":\"\",\"TD\":\"IH\",\"COMMENT\":\"02/12/2018\",\"STANME\":\"NAIRN\"}";
Smart smart = Smart.parseJSON(new JSONObject(json));
assertEquals(SmartStepType.BETWEEN, smart.getStepType());
assertEquals("7910", smart.getFromBerth());
assertEquals("7904", smart.getToBerth());
assertEquals("01125", smart.getStanox());
assertEquals(SmartEvent.ARRIVE_UP, smart.getEvent());
assertEquals("1", smart.getPlatform());
assertEquals("", smart.getToLine());
assertEquals(59, smart.getBerthOffset());
assertEquals("", smart.getRoute());
assertEquals("", smart.getFromLine());
assertEquals("IH", smart.getTd());
assertEquals("02/12/2018", smart.getComment());
assertEquals("NAIRN", smart.getStationName());
}
@Test
public void testSmartInvalidEnumVal2(){
String json = "{\"STEPTYPE\":\"B\",\"FROMBERTH\":\"7910\",\"TOBERTH\":\"7904\",\"STANOX\":\"01125\",\"EVENT\":\"Z\",\"PLATFORM\":\"1\"," +
"\"TOLINE\":\"\",\"BERTHOFFSET\":\"+59\",\"ROUTE\":\"\",\"FROMLINE\":\"\",\"TD\":\"IH\",\"COMMENT\":\"02/12/2018\",\"STANME\":\"NAIRN\"}";
Smart smart = Smart.parseJSON(new JSONObject(json));
assertEquals(SmartStepType.BETWEEN, smart.getStepType());
assertEquals("7910", smart.getFromBerth());
assertEquals("7904", smart.getToBerth());
assertEquals("01125", smart.getStanox());
assertNull(smart.getEvent());
assertEquals("1", smart.getPlatform());
assertEquals("", smart.getToLine());
assertEquals(59, smart.getBerthOffset());
assertEquals("", smart.getRoute());
assertEquals("", smart.getFromLine());
assertEquals("IH", smart.getTd());
assertEquals("02/12/2018", smart.getComment());
assertEquals("NAIRN", smart.getStationName());
}
@Test
public void testSmartNormalCase3(){
String json = "{\"STEPTYPE\":\"B\",\"FROMBERTH\":\"7910\",\"TOBERTH\":\"7904\",\"STANOX\":\"01125\",\"EVENT\":\"A\",\"PLATFORM\":\"1\"," +
"\"TOLINE\":\"\",\"BERTHOFFSET\":\"-59\",\"ROUTE\":\"\",\"FROMLINE\":\"\",\"TD\":\"IH\",\"COMMENT\":\"02/12/2018\",\"STANME\":\"NAIRN\"}";
Smart smart = Smart.parseJSON(json);
assertEquals(SmartStepType.BETWEEN, smart.getStepType());
assertEquals("7910", smart.getFromBerth());
assertEquals("7904", smart.getToBerth());
assertEquals("01125", smart.getStanox());
assertEquals(SmartEvent.ARRIVE_UP, smart.getEvent());
assertEquals("1", smart.getPlatform());
assertEquals("", smart.getToLine());
assertEquals(-59, smart.getBerthOffset());
assertEquals("", smart.getRoute());
assertEquals("", smart.getFromLine());
assertEquals("IH", smart.getTd());
assertEquals("02/12/2018", smart.getComment());
assertEquals("NAIRN", smart.getStationName());
}
@Test
public void testSmartInvalidEnumVal3(){
String json = "{\"STEPTYPE\":\"B\",\"FROMBERTH\":\"7910\",\"TOBERTH\":\"7904\",\"STANOX\":\"01125\",\"EVENT\":\"Z\",\"PLATFORM\":\"1\"," +
"\"TOLINE\":\"\",\"BERTHOFFSET\":\"-59\",\"ROUTE\":\"\",\"FROMLINE\":\"\",\"TD\":\"IH\",\"COMMENT\":\"02/12/2018\",\"STANME\":\"NAIRN\"}";
Smart smart = Smart.parseJSON(json);
assertEquals(SmartStepType.BETWEEN, smart.getStepType());
assertEquals("7910", smart.getFromBerth());
assertEquals("7904", smart.getToBerth());
assertEquals("01125", smart.getStanox());
assertNull(smart.getEvent());
assertEquals("1", smart.getPlatform());
assertEquals("", smart.getToLine());
assertEquals(-59, smart.getBerthOffset());
assertEquals("", smart.getRoute());
assertEquals("", smart.getFromLine());
assertEquals("IH", smart.getTd());
assertEquals("02/12/2018", smart.getComment());
assertEquals("NAIRN", smart.getStationName());
}
@Test
public void testSmartNormalCase4(){
String json = "{\"STEPTYPE\":\"B\",\"FROMBERTH\":\"7910\",\"TOBERTH\":\"7904\",\"STANOX\":\"01125\",\"EVENT\":\"A\",\"PLATFORM\":\"1\"," +
"\"TOLINE\":\"\",\"BERTHOFFSET\":\"-59\",\"ROUTE\":\"\",\"FROMLINE\":\"\",\"TD\":\"IH\",\"COMMENT\":\"02/12/2018\",\"STANME\":\"NAIRN\"}";
Smart smart = Smart.parseJSON(new JSONObject(json));
assertEquals(SmartStepType.BETWEEN, smart.getStepType());
assertEquals("7910", smart.getFromBerth());
assertEquals("7904", smart.getToBerth());
assertEquals("01125", smart.getStanox());
assertEquals(SmartEvent.ARRIVE_UP, smart.getEvent());
assertEquals("1", smart.getPlatform());
assertEquals("", smart.getToLine());
assertEquals(-59, smart.getBerthOffset());
assertEquals("", smart.getRoute());
assertEquals("", smart.getFromLine());
assertEquals("IH", smart.getTd());
assertEquals("02/12/2018", smart.getComment());
assertEquals("NAIRN", smart.getStationName());
}
@Test
public void testSmartInvalidEnumVal4(){
String json = "{\"STEPTYPE\":\"B\",\"FROMBERTH\":\"7910\",\"TOBERTH\":\"7904\",\"STANOX\":\"01125\",\"EVENT\":\"Z\",\"PLATFORM\":\"1\"," +
"\"TOLINE\":\"\",\"BERTHOFFSET\":\"-59\",\"ROUTE\":\"\",\"FROMLINE\":\"\",\"TD\":\"IH\",\"COMMENT\":\"02/12/2018\",\"STANME\":\"NAIRN\"}";
Smart smart = Smart.parseJSON(new JSONObject(json));
assertEquals(SmartStepType.BETWEEN, smart.getStepType());
assertEquals("7910", smart.getFromBerth());
assertEquals("7904", smart.getToBerth());
assertEquals("01125", smart.getStanox());
assertNull(smart.getEvent());
assertEquals("1", smart.getPlatform());
assertEquals("", smart.getToLine());
assertEquals(-59, smart.getBerthOffset());
assertEquals("", smart.getRoute());
assertEquals("", smart.getFromLine());
assertEquals("IH", smart.getTd());
assertEquals("02/12/2018", smart.getComment());
assertEquals("NAIRN", smart.getStationName());
}
@Test
public void testSmartNormalCase6(){
String json = "{\"STEPTYPE\":\"B\",\"FROMBERTH\":\"7910\",\"TOBERTH\":\"7904\",\"STANOX\":\"01125\",\"EVENT\":\"A\",\"PLATFORM\":\"1\"," +
"\"TOLINE\":\"\",\"BERTHOFFSET\":\"59\",\"ROUTE\":\"\",\"FROMLINE\":\"\",\"TD\":\"IH\",\"COMMENT\":\"02/12/2018\",\"STANME\":\"NAIRN\"}";
Smart smart = Smart.parseJSON(json);
assertEquals(SmartStepType.BETWEEN, smart.getStepType());
assertEquals("7910", smart.getFromBerth());
assertEquals("7904", smart.getToBerth());
assertEquals("01125", smart.getStanox());
assertEquals(SmartEvent.ARRIVE_UP, smart.getEvent());
assertEquals("1", smart.getPlatform());
assertEquals("", smart.getToLine());
assertEquals(59, smart.getBerthOffset());
assertEquals("", smart.getRoute());
assertEquals("", smart.getFromLine());
assertEquals("IH", smart.getTd());
assertEquals("02/12/2018", smart.getComment());
assertEquals("NAIRN", smart.getStationName());
}
@Test
public void testSmartInvalidEnumVal6(){
String json = "{\"STEPTYPE\":\"B\",\"FROMBERTH\":\"7910\",\"TOBERTH\":\"7904\",\"STANOX\":\"01125\",\"EVENT\":\"Z\",\"PLATFORM\":\"1\"," +
"\"TOLINE\":\"\",\"BERTHOFFSET\":\"59\",\"ROUTE\":\"\",\"FROMLINE\":\"\",\"TD\":\"IH\",\"COMMENT\":\"02/12/2018\",\"STANME\":\"NAIRN\"}";
Smart smart = Smart.parseJSON(json);
assertEquals(SmartStepType.BETWEEN, smart.getStepType());
assertEquals("7910", smart.getFromBerth());
assertEquals("7904", smart.getToBerth());
assertEquals("01125", smart.getStanox());
assertNull(smart.getEvent());
assertEquals("1", smart.getPlatform());
assertEquals("", smart.getToLine());
assertEquals(59, smart.getBerthOffset());
assertEquals("", smart.getRoute());
assertEquals("", smart.getFromLine());
assertEquals("IH", smart.getTd());
assertEquals("02/12/2018", smart.getComment());
assertEquals("NAIRN", smart.getStationName());
}
@Test
public void testSmartNormalCase5(){
String json = "{\"STEPTYPE\":\"B\",\"FROMBERTH\":\"7910\",\"TOBERTH\":\"7904\",\"STANOX\":\"01125\",\"EVENT\":\"A\",\"PLATFORM\":\"1\"," +
"\"TOLINE\":\"\",\"BERTHOFFSET\":\"59\",\"ROUTE\":\"\",\"FROMLINE\":\"\",\"TD\":\"IH\",\"COMMENT\":\"02/12/2018\",\"STANME\":\"NAIRN\"}";
Smart smart = Smart.parseJSON(new JSONObject(json));
assertEquals(SmartStepType.BETWEEN, smart.getStepType());
assertEquals("7910", smart.getFromBerth());
assertEquals("7904", smart.getToBerth());
assertEquals("01125", smart.getStanox());
assertEquals(SmartEvent.ARRIVE_UP, smart.getEvent());
assertEquals("1", smart.getPlatform());
assertEquals("", smart.getToLine());
assertEquals(59, smart.getBerthOffset());
assertEquals("", smart.getRoute());
assertEquals("", smart.getFromLine());
assertEquals("IH", smart.getTd());
assertEquals("02/12/2018", smart.getComment());
assertEquals("NAIRN", smart.getStationName());
}
@Test
public void testSmartInvalidEnumVal5(){
String json = "{\"STEPTYPE\":\"B\",\"FROMBERTH\":\"7910\",\"TOBERTH\":\"7904\",\"STANOX\":\"01125\",\"EVENT\":\"Z\",\"PLATFORM\":\"1\"," +
"\"TOLINE\":\"\",\"BERTHOFFSET\":\"59\",\"ROUTE\":\"\",\"FROMLINE\":\"\",\"TD\":\"IH\",\"COMMENT\":\"02/12/2018\",\"STANME\":\"NAIRN\"}";
Smart smart = Smart.parseJSON(new JSONObject(json));
assertEquals(SmartStepType.BETWEEN, smart.getStepType());
assertEquals("7910", smart.getFromBerth());
assertEquals("7904", smart.getToBerth());
assertEquals("01125", smart.getStanox());
assertNull(smart.getEvent());
assertEquals("1", smart.getPlatform());
assertEquals("", smart.getToLine());
assertEquals(59, smart.getBerthOffset());
assertEquals("", smart.getRoute());
assertEquals("", smart.getFromLine());
assertEquals("IH", smart.getTd());
assertEquals("02/12/2018", smart.getComment());
assertEquals("NAIRN", smart.getStationName());
}
}

29
src/test/java/org/leolo/nrdatad/SmartEnumTest.java

@ -0,0 +1,29 @@
package org.leolo.nrdatad;
import org.junit.Test;
import org.leolo.nrdatad.model.SmartEvent;
import org.leolo.nrdatad.model.SmartStepType;
import static org.junit.Assert.*;
public class SmartEnumTest {
@Test
public void testSmartStepType(){
assertEquals(SmartStepType.BETWEEN, SmartStepType.parseCode("B"));
assertEquals(SmartStepType.BETWEEN, SmartStepType.parseCode("b"));
assertNull(SmartStepType.parseCode("Q"));
assertNull(SmartStepType.parseCode("X"));
assertNull(SmartStepType.parseCode(""));
}
@Test
public void testSmartEvent(){
assertEquals(SmartEvent.ARRIVE_UP, SmartEvent.parseCode("A"));
assertEquals(SmartEvent.ARRIVE_UP, SmartEvent.parseCode("a"));
assertNull(SmartEvent.parseCode("Q"));
assertNull(SmartEvent.parseCode("X"));
assertNull(SmartEvent.parseCode(""));
}
}

35
src/test/java/org/leolo/nrdatad/UtilTest.java

@ -0,0 +1,35 @@
package org.leolo.nrdatad;
import org.junit.Test;
import org.leolo.nrdatad.util.JSONUtil;
import static org.junit.Assert.*;
public class UtilTest {
@Test public void testJSONUtilParseIntNormal(){
assertEquals(10, JSONUtil.parseInt("10"));
assertEquals(10, JSONUtil.parseInt("+10"));
assertEquals(-10, JSONUtil.parseInt("-10"));
}
@Test(expected = NumberFormatException.class) public void testJSONUtilParseIntError1(){
JSONUtil.parseInt("abcd");
}
@Test(expected = NumberFormatException.class) public void testJSONUtilParseIntError2(){
JSONUtil.parseInt("");
}
@Test(expected = NullPointerException.class) public void testJSONUtilParseIntError3(){
JSONUtil.parseInt(null);
}
@Test(expected = NumberFormatException.class) public void testJSONUtilParseIntError4(){
JSONUtil.parseInt("+");
}
@Test(expected = NumberFormatException.class) public void testJSONUtilParseIntError5(){
JSONUtil.parseInt("+abcd");
}
@Test(expected = NumberFormatException.class) public void testJSONUtilParseIntError6(){
JSONUtil.parseInt("+2200000000");
}
}

42
src/test/java/org/leolo/nrdatad/db/test/DatabaseManager.java

@ -0,0 +1,42 @@
package org.leolo.nrdatad.db.test;
import org.leolo.nrdatad.db.CorpusDao;
import org.leolo.nrdatad.db.MetadataDao;
import org.leolo.nrdatad.db.SmartDao;
import java.sql.Connection;
import java.sql.SQLException;
public class DatabaseManager implements org.leolo.nrdatad.db.DatabaseManager {
public void initPool() {
}
@Override
public boolean checkConnection() {
return true;
}
@Override
public Connection getConnection() throws SQLException {
throw new RuntimeException("Function not supported by stub");
}
@Override
public SmartDao getSmartDao() {
return null;
}
@Override
public MetadataDao getMetadataDao() {
return null;
}
@Override
public CorpusDao getCORPUSDao() {
return null;
}
}

40
src/test/java/org/leolo/nrdatad/db/test/MetadataDao.java

@ -0,0 +1,40 @@
package org.leolo.nrdatad.db.test;
import org.jetbrains.annotations.NotNull;
import org.leolo.nrdatad.db.DatabaseManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Set;
import java.util.function.BiConsumer;
public class MetadataDao extends org.leolo.nrdatad.db.MetadataDao {
private HashMap<String, String> dataMap = new HashMap<>();
public MetadataDao(DatabaseManager manager) {
super(manager);
}
@Override
public String getMetadata(String key, String defaultValue) throws SQLException {
if(dataMap.containsKey(key))
return dataMap.get(key);
return defaultValue;
}
@Override
public void updateMetadata(String key, @NotNull String value) throws SQLException {
dataMap.put(key, value);
}
@Override
public Set<String> getKeys() throws SQLException {
return dataMap.keySet();
}
@Override
public void forEach(BiConsumer<String, String> action) throws SQLException {
dataMap.forEach(action);
}
}

20
src/test/java/org/leolo/nrdatad/util/RangeTest.java

@ -0,0 +1,20 @@
package org.leolo.nrdatad.util;
import org.junit.Test;
import static org.junit.Assert.*;
public class RangeTest {
@Test
public void basicInteger1(){
Range<Integer> range = new Range<>(1,2);
assertEquals(1, range.getLowerBound().intValue());
assertEquals(2, range.getUpperBound().intValue());
range = new Range<>(2,1);
assertEquals(1, range.getLowerBound().intValue());
assertEquals(2, range.getUpperBound().intValue());
range = new Range<>(2,2);
assertEquals(2, range.getLowerBound().intValue());
assertEquals(2, range.getUpperBound().intValue());
}
}
Loading…
Cancel
Save