diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..24dceb6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +# Changelog for Accounting Analytics Backend Connector for PostgreSQL + + +## [v1.0.0-SNAPSHOT] + +- First Release diff --git a/README.md b/README.md index ef8f1b2..299fcc7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,71 @@ -# accounting-analytics-persistence-postgresql +# Accounting Analytics Backend Connector for PostgreSQL + +Accounting Analytics Backend Connector for PostgreSQL + +## Built With + +* [OpenJDK](https://openjdk.java.net/) - The JDK used +* [Maven](https://maven.apache.org/) - Dependency Management + +## Documentation + +[Accounting Analytics Backend Connector for PostgreSQL](https://wiki.gcube-system.org/gcube/Accounting_Analytics) + +## Change log + +See [Releases](https://code-repo.d4science.org/gCubeSystem/accounting-analytics-persistence-postgresql/releases). + +## Authors + +* **Luca Frosini** ([ORCID](https://orcid.org/0000-0003-3183-2291)) - [ISTI-CNR Infrascience Group](http://nemis.isti.cnr.it/groups/infrascience) + +## How to Cite this Software + +Tell people how to cite this software. +* Cite an associated paper? +* Use a specific BibTeX entry for the software? + + + @Manual{, + title = {Accounting Analytics Backend Connector for PostgreSQL}, + author = {{Frosini, Luca}}, + organization = {ISTI - CNR}, + address = {Pisa, Italy}, + year = 2021, + url = {http://www.gcube-system.org/} + } + +## License + +This project is licensed under the EUPL V.1.2 License - see the [LICENSE.md](LICENSE.md) file for details. + + +## About the gCube Framework +This software is part of the [gCubeFramework](https://www.gcube-system.org/ "gCubeFramework"): an +open-source software toolkit used for building and operating Hybrid Data +Infrastructures enabling the dynamic deployment of Virtual Research Environments +by favouring the realisation of reuse oriented policies. + +The projects leading to this software have received funding from a series of European Union programmes including: + +- the Sixth Framework Programme for Research and Technological Development + - DILIGENT (grant no. 004260). +- the Seventh Framework Programme for research, technological development and demonstration + - D4Science (grant no. 212488); + - D4Science-II (grant no.239019); + - ENVRI (grant no. 283465); + - iMarine(grant no. 283644); + - EUBrazilOpenBio (grant no. 288754). +- the H2020 research and innovation programme + - SoBigData (grant no. 654024); + - PARTHENOS (grant no. 654119); + - EGIEngage (grant no. 654142); + - ENVRIplus (grant no. 654182); + - BlueBRIDGE (grant no. 675680); + - PerformFish (grant no. 727610); + - AGINFRAplus (grant no. 731001); + - DESIRA (grant no. 818194); + - ARIADNEplus (grant no. 823914); + - RISIS2 (grant no. 824091); + -Accounting Analytics Backend Connector for PostgreSQL \ No newline at end of file diff --git a/pom.xml b/pom.xml index 46b5426..63878be 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,11 @@ accounting-analytics [3.0.0-SNAPSHOT, 4.0.0-SNAPSHOT) + + org.gcube.accounting + accounting-postgresql-utilities + [1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT) + org.slf4j slf4j-api @@ -56,7 +61,7 @@ postgresql 42.2.19 - + junit junit diff --git a/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/AccountingPersistenceQueryPostgreSQL.java b/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/AccountingPersistenceQueryPostgreSQL.java index 5cece82..78b5137 100644 --- a/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/AccountingPersistenceQueryPostgreSQL.java +++ b/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/AccountingPersistenceQueryPostgreSQL.java @@ -8,7 +8,6 @@ import java.sql.ResultSet; import java.sql.Statement; import java.time.OffsetDateTime; import java.util.Calendar; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -30,6 +29,9 @@ import org.gcube.accounting.analytics.persistence.AccountingPersistenceBackendQu import org.gcube.accounting.datamodel.aggregation.AggregatedServiceUsageRecord; import org.gcube.accounting.datamodel.usagerecords.ServiceUsageRecord; import org.gcube.accounting.persistence.AccountingPersistenceConfiguration; +import org.gcube.accounting.utility.postgresql.RecordToDBFields; +import org.gcube.accounting.utility.postgresql.RecordToDBConnection; +import org.gcube.accounting.utility.postgresql.RecordToDBMapping; import org.gcube.documentstore.records.AggregatedRecord; import org.gcube.documentstore.records.RecordUtility; import org.json.JSONObject; @@ -41,7 +43,7 @@ import org.slf4j.LoggerFactory; */ public class AccountingPersistenceQueryPostgreSQL implements AccountingPersistenceBackendQuery { - private static final Logger logger = LoggerFactory.getLogger(AccountingPersistenceQueryPostgreSQL.class); + protected static final Logger logger = LoggerFactory.getLogger(AccountingPersistenceQueryPostgreSQL.class); public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS Z"; @@ -50,40 +52,32 @@ public class AccountingPersistenceQueryPostgreSQL implements AccountingPersisten protected AccountingPersistenceBackendQueryConfiguration configuration; - protected Map>, UsageRecordDBInfo> usageRecordDB; - static { // One Record per package is enough RecordUtility.addRecordPackage(ServiceUsageRecord.class.getPackage()); RecordUtility.addRecordPackage(AggregatedServiceUsageRecord.class.getPackage()); - Map>> aggregatedRecords = RecordUtility.getAggregatedRecordClassesFound(); - for(String typeName : aggregatedRecords.keySet()) { - try { - Class> clz = aggregatedRecords.get(typeName); - UsageRecordToDBMapping.getRecordToDB(clz); - } catch (Exception e) { - new RuntimeException(e); - } - } } protected Connection getConnection(Class> clz) throws Exception { - UsageRecordDBInfo usageRecordDBInfo = usageRecordDB.get(clz); - if(usageRecordDBInfo == null) { - usageRecordDBInfo = new UsageRecordDBInfo(clz, configuration); - usageRecordDB.put(clz, usageRecordDBInfo); + RecordToDBConnection recordDBInfo = RecordToDBMapping.getRecordDBInfo(clz); + if(recordDBInfo == null) { + RecordToDBMapping.addRecordToDB(clz, configuration); } - return usageRecordDBInfo.getConnection(); + return recordDBInfo.getConnection(); } - - @Override public void prepareConnection(AccountingPersistenceBackendQueryConfiguration configuration) throws Exception { - logger.trace("prepareConnection"); this.configuration = configuration; - // this.baseURL = configuration.getProperty(URL_PROPERTY_KEY); - this.usageRecordDB = new HashMap<>(); + Map>> aggregatedRecords = RecordUtility.getAggregatedRecordClassesFound(); + for(String typeName : aggregatedRecords.keySet()) { + try { + Class> clz = aggregatedRecords.get(typeName); + RecordToDBMapping.getRecordToDB(clz); + } catch (Exception e) { + new RuntimeException(e); + } + } } public SortedMap getTimeSeries(Class> clz, @@ -103,7 +97,7 @@ public class AccountingPersistenceQueryPostgreSQL implements AccountingPersisten String sql = query.getTimeSeriesQuery(); List requestedTableField = query.getRequestedTableField(); - RecordToDBMapper recordToDBMapper = query.getRecordToDBMapper(); + RecordToDBFields recordToDBMapper = query.getRecordToDBMapper(); ResultSet resultSet = statement.executeQuery(sql); @@ -114,7 +108,7 @@ public class AccountingPersistenceQueryPostgreSQL implements AccountingPersisten JSONObject jsonObject = new JSONObject(); for(String tableField : requestedTableField) { - String usageRecordField = recordToDBMapper.getUsageRecordField(tableField); + String usageRecordField = recordToDBMapper.getRecordField(tableField); Object object = resultSet.getObject(tableField); jsonObject.put(usageRecordField, object); } diff --git a/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/Query.java b/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/Query.java index 081e8f8..4dd3bc1 100644 --- a/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/Query.java +++ b/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/Query.java @@ -14,6 +14,8 @@ import org.gcube.accounting.analytics.TemporalConstraint.AggregationMode; import org.gcube.accounting.analytics.TemporalConstraint.CalendarEnum; import org.gcube.accounting.datamodel.UsageRecord; import org.gcube.accounting.datamodel.aggregation.AggregatedServiceUsageRecord; +import org.gcube.accounting.utility.postgresql.RecordToDBFields; +import org.gcube.accounting.utility.postgresql.RecordToDBMapping; import org.gcube.documentstore.records.AggregatedRecord; public class Query { @@ -22,7 +24,7 @@ public class Query { public static final String DATE_OF_TIMESERIES_AS_FIELD = AggregatedRecord.START_TIME; private Class> clz; - private final RecordToDBMapper recordToDBMapper; + private final RecordToDBFields recordToDBMapper; private List requestedTableField; private StringBuffer stringBuffer; @@ -33,7 +35,7 @@ public class Query { public Query(Class> clz) throws Exception { this.clz = clz; - this.recordToDBMapper = UsageRecordToDBMapping.getRecordToDB(clz); + this.recordToDBMapper = RecordToDBMapping.getRecordToDB(clz); } public List getRequestedTableField() { @@ -60,7 +62,7 @@ public class Query { } - public RecordToDBMapper getRecordToDBMapper() { + public RecordToDBFields getRecordToDBMapper() { return recordToDBMapper; } diff --git a/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/RecordToDBMapper.java b/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/RecordToDBMapper.java deleted file mode 100644 index 15b701d..0000000 --- a/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/RecordToDBMapper.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.gcube.accounting.analytics.persistence.postgresql; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.gcube.documentstore.records.AggregatedRecord; -import org.gcube.documentstore.records.Record; - -public class RecordToDBMapper { - - protected static String getRecordTypeByClass(Class> clz) { - try { - Record r = clz.newInstance(); - return r.getRecordType(); - }catch (Exception e) { - String type = clz.getSimpleName(); - type = type.replace("Abstract", ""); - type = type.replace("Aggregated", ""); - return type; - } - } - - protected static String getKey(String fieldName) { - StringBuffer stringBuffer = new StringBuffer(); - int lenght = fieldName.length(); - boolean lastLowerCase = true; - for (int i=0; i> clz; - - protected final String typeName; - protected final String tableName; - - protected final Map tableFieldToUsageRecordField; - protected final Map usageRecordFieldToTableField; - - public RecordToDBMapper(Class> clz) throws Exception { - this.clz = clz; - this.typeName = getRecordTypeByClass(clz); - this.tableName = typeName.toLowerCase(); - this.tableFieldToUsageRecordField = new HashMap<>(); - this.usageRecordFieldToTableField = new HashMap<>(); - mapFields(); - } - - public RecordToDBMapper(String typeName, Class> clz) throws Exception { - this.clz = clz; - this.typeName = typeName; - this.tableName = typeName.toLowerCase(); - this.tableFieldToUsageRecordField = new HashMap<>(); - this.usageRecordFieldToTableField = new HashMap<>(); - mapFields(); - } - - protected void mapFields() throws Exception { - Set requiredFields = clz.newInstance().getRequiredFields(); - for(String usageRecordField : requiredFields) { - String dbField = getKey(usageRecordField); - tableFieldToUsageRecordField.put(dbField, usageRecordField); - usageRecordFieldToTableField.put(usageRecordField, dbField); - } - } - - public String getTableField(String usageRecordField) { - return usageRecordFieldToTableField.get(usageRecordField); - } - - public String getUsageRecordField(String tableField) { - String ret = tableFieldToUsageRecordField.get(tableField); - if(ret==null && usageRecordFieldToTableField.keySet().contains(tableField)) { - ret = tableField; - } - return ret; - } - - public String getTypeName() { - return typeName; - } - - public String getTableName() { - return tableName; - } - -} diff --git a/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/UsageRecordDBInfo.java b/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/UsageRecordDBInfo.java deleted file mode 100644 index cf81b28..0000000 --- a/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/UsageRecordDBInfo.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.gcube.accounting.analytics.persistence.postgresql; - -import java.sql.Connection; -import java.sql.DriverManager; - -import org.gcube.accounting.analytics.persistence.AccountingPersistenceBackendQueryConfiguration; -import org.gcube.accounting.persistence.AccountingPersistenceConfiguration; -import org.gcube.documentstore.records.AggregatedRecord; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class UsageRecordDBInfo { - - private static final Logger logger = LoggerFactory.getLogger(UsageRecordDBInfo.class); - - public static final String URL_PROPERTY_KEY = AccountingPersistenceConfiguration.URL_PROPERTY_KEY; - public static final String DB_SUFFIX = "-db"; - public static final String USERNAME_SUFFIX = "-username"; - public static final String PASSWORD_SUFFIX = "-password"; - - private final String baseURL; - private final String dbName; - private final String url; - private final String username; - private final String password; - - protected final Class> clz; - protected final String typeName; - - public UsageRecordDBInfo(Class> clz, AccountingPersistenceBackendQueryConfiguration configuration) throws Exception { - this.clz = clz; - this.typeName = UsageRecordToDBMapping.getRecordToDB(clz).getTypeName(); - - this.baseURL = configuration.getProperty(URL_PROPERTY_KEY); - this.dbName = configuration.getProperty(typeName+DB_SUFFIX); - this.url = baseURL + "/" + dbName; - - this.username = configuration.getProperty(typeName+USERNAME_SUFFIX); - this.password = configuration.getProperty(typeName+PASSWORD_SUFFIX); - - } - - protected Connection getConnection() throws Exception { - Class.forName("org.postgresql.Driver"); - Connection connection = DriverManager.getConnection(url, username, password); - logger.trace("Database {} opened successfully", url); - connection.setAutoCommit(false); - return connection; - } - -} diff --git a/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/UsageRecordToDBMapping.java b/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/UsageRecordToDBMapping.java deleted file mode 100644 index bfa3b28..0000000 --- a/src/main/java/org/gcube/accounting/analytics/persistence/postgresql/UsageRecordToDBMapping.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.gcube.accounting.analytics.persistence.postgresql; - -import java.util.HashMap; -import java.util.Map; - -import org.gcube.documentstore.records.AggregatedRecord; - -public class UsageRecordToDBMapping { - - protected final static Map>, RecordToDBMapper> classToRecordToDBMapper; - - static { - classToRecordToDBMapper = new HashMap<>(); - } - - public static synchronized RecordToDBMapper getRecordToDB(Class> clz) throws Exception { - RecordToDBMapper recordToDBMapper = classToRecordToDBMapper.get(clz); - if(recordToDBMapper==null) { - recordToDBMapper = new RecordToDBMapper(clz); - classToRecordToDBMapper.put(clz, recordToDBMapper); - } - return recordToDBMapper; - } - -}