From 8a88e367df29f01757e45b2d7637509c49055fae Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 18 Dec 2013 00:46:40 -0800 Subject: [PATCH 01/61] Initial commit --- LICENSE | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 4 ++ 2 files changed, 206 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..e06d20818 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/README.md b/README.md new file mode 100644 index 000000000..c5b8d2b6c --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +li.strolch.persistence.postgresql +================================= + +PostgreSQL persistence implementation for Strolch From 0ea999d92116cb44bad9ad70351ccb7bac78cd8e Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 18 Dec 2013 16:29:45 +0100 Subject: [PATCH 02/61] [New] Initial commit --- .gitignore | 4 + LICENSE | 8 +- README.md | 54 ++++- pom.xml | 86 ++++++++ .../persistence/postgresql/AbstractDao.java | 96 +++++++++ .../postgresql/DbConnectionCheck.java | 73 +++++++ .../postgresql/DbSchemaVersionCheck.java | 201 ++++++++++++++++++ .../postgresql/ModificationResult.java | 60 ++++++ .../postgresql/PostgreSqlOrderDao.java | 33 +++ .../PostgreSqlPersistenceHandler.java | 122 +++++++++++ .../postgresql/PostgreSqlResourceDao.java | 33 +++ .../PostgreSqlStrolchTransaction.java | 102 +++++++++ src/main/resources/db_schema_0.1.0_drop.sql | 5 + .../resources/db_schema_0.1.0_initial.sql | 33 +++ src/main/resources/db_version.properties | 2 + .../dao/test/AbstractDaoImplTest.java | 54 +++++ .../dao/test/ObserverUpdateTest.java | 98 +++++++++ .../dao/test/PostgreSqlOrderDaoTest.java | 92 ++++++++ .../dao/test/PostgreSqlResourceDaoTest.java | 92 ++++++++ src/test/resources/log4j.xml | 29 +++ .../runtime/config/StrolchConfiguration.xml | 27 +++ 21 files changed, 1298 insertions(+), 6 deletions(-) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/li/strolch/persistence/postgresql/AbstractDao.java create mode 100644 src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java create mode 100644 src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java create mode 100644 src/main/java/li/strolch/persistence/postgresql/ModificationResult.java create mode 100644 src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java create mode 100644 src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java create mode 100644 src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java create mode 100644 src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java create mode 100644 src/main/resources/db_schema_0.1.0_drop.sql create mode 100644 src/main/resources/db_schema_0.1.0_initial.sql create mode 100644 src/main/resources/db_version.properties create mode 100644 src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java create mode 100644 src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java create mode 100644 src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java create mode 100644 src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java create mode 100644 src/test/resources/log4j.xml create mode 100644 src/test/resources/runtime/config/StrolchConfiguration.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..b284c6517 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +target/ +.project +.settings +.classpath diff --git a/LICENSE b/LICENSE index e06d20818..d64569567 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ -Apache License + + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -178,7 +179,7 @@ Apache License APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" + boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -186,7 +187,7 @@ Apache License same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -199,4 +200,3 @@ Apache License WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - diff --git a/README.md b/README.md index c5b8d2b6c..544187790 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,54 @@ li.strolch.persistence.postgresql -================================= +======================================================================= -PostgreSQL persistence implementation for Strolch +PostgreSQL Persistence Implementation for Strolch + + +Setup +======================================================================= +1. Install PostgreSQL version with at least version 9.1: + $ sudo aptitude install postgresql postgresql-client +2. Set a password for user 'postgres' + $ sudo -u postgres psql postgres + postgres=# \password postgres +3. Create the user and DB: + $ sudo su - postgres + postgres=# create user testUser with password 'test'; + postgres=# create database testdb; + postgres=# GRANT ALL PRIVILEGES ON DATABASE testdb to testuser; + postgres=# GRANT CONNECT ON DATABASE testdb TO testuser ; + +4. Added new component, setting properties for PostgreSQL DB: + + PersistenceHandler + li.strolch.persistence.api.StrolchPersistenceHandler + li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler + + false + jdbc:postgresql://localhost/testdb + testUser + test + + + +5. Create tables, or allow strolch to due it for you. + + +Appendix +======================================================================= +1. To drop the user and DB: + postgres=# revoke ALL PRIVILEGES ON DATABASE testdb from testuser; + postgres=# drop user testuser; + postgres=# drop database testdb; +2. Create a database: + $ createdb -p 5432 -O drupal -U drupal -E UTF8 testingsiteone -T template0 +3. Dropping the database + $ dropdb -p 5432 -U drupal testingsiteone +4. Dumping the database + $ pg_dump -p 5432 -h localhost -Fc -U drupal --no-owner testingsiteone > /tmp/testingsiteone_$(date +"%Y-%m-%d_%s").pgdump +5. Restoring the database + $ pg_restore -p 5432 -h localhost -Fc -d testingsiteone -U drupal --no-owner < /tmp/path-to-the-file.pgdump + +References +======================================================================= +http://www.pixelite.co.nz/article/installing-and-configuring-postgresql-91-ubuntu-1204-local-drupal-development \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000..70d4636c2 --- /dev/null +++ b/pom.xml @@ -0,0 +1,86 @@ + + + + li.strolch + li.strolch.parent + 0.1.0-SNAPSHOT + ../li.strolch.parent/pom.xml + + + 4.0.0 + + li.strolch.persistence.postgresql + + Reference Persistence Implementation for Strolch + Reference Persistence Implementation for Strolch + + https://github.com/eitch/li.strolch.persistence.postgresql + + 2011 + + + Github Issues + https://github.com/eitch/li.strolch.persistence.postgresql/issues + + + + scm:git:https://github.com/eitch/li.strolch.persistence.postgresql.git + scm:git:git@github.com:eitch/li.strolch.persistence.postgresql.git + https://github.com/eitch/li.strolch.persistence.postgresql + + + + + + li.strolch + li.strolch.model + + + li.strolch + li.strolch.runtime + + + li.strolch + li.strolch.persistence.api + + + + org.postgresql + postgresql + 9.3-1100-jdbc41 + + + + li.strolch + li.strolch.testbase + test + + + + + + + + org.apache.maven.plugins + maven-eclipse-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + org.apache.maven.plugins + maven-site-plugin + + + + \ No newline at end of file diff --git a/src/main/java/li/strolch/persistence/postgresql/AbstractDao.java b/src/main/java/li/strolch/persistence/postgresql/AbstractDao.java new file mode 100644 index 000000000..16b474dc8 --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/AbstractDao.java @@ -0,0 +1,96 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import li.strolch.model.StrolchElement; +import li.strolch.persistence.api.StrolchDao; +import li.strolch.persistence.api.StrolchTransaction; + +public abstract class AbstractDao implements StrolchDao { + + protected AbstractDao(StrolchTransaction tx) { + PostgreSqlStrolchTransaction strolchTx = (PostgreSqlStrolchTransaction) tx; + } + + protected abstract String getClassType(); + + @Override + public Set queryKeySet() { + Set keys = new HashSet<>(); + Set types = queryTypes(); + for (String type : types) { + keys.addAll(queryKeySet(type)); + } + return keys; + } + + @Override + public Set queryKeySet(String type) { + return null; + } + + @Override + public Set queryTypes() { + return null; + } + + @Override + public T queryBy(String type, String id) { + return null; + } + + @Override + public List queryAll() { + return null; + } + + @Override + public List queryAll(String type) { + return null; + } + + @Override + public void save(T object) { + } + + @Override + public void saveAll(List objects) { + } + + @Override + public void update(T object) { + } + + @Override + public void updateAll(List objects) { + } + + @Override + public void remove(T object) { + } + + @Override + public void removeAll(List objects) { + } + + @Override + public void remove(String type, String id) { + } +} diff --git a/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java b/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java new file mode 100644 index 000000000..bf8263721 --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java @@ -0,0 +1,73 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.persistence.api.DbConnectionInfo; +import li.strolch.runtime.configuration.StrolchConfigurationException; + +/** + * @author Robert von Burg + * + */ +public class DbConnectionCheck { + + private static final Logger logger = LoggerFactory.getLogger(DbConnectionCheck.class); + private Map connetionInfoMap; + + /** + * @param connetionInfoMap + */ + public DbConnectionCheck(Map connetionInfoMap) { + this.connetionInfoMap = connetionInfoMap; + } + + public void checkConnections() { + Collection values = this.connetionInfoMap.values(); + for (DbConnectionInfo connectionInfo : values) { + String url = connectionInfo.getUrl(); + String username = connectionInfo.getUsername(); + String password = connectionInfo.getPassword(); + + try (Connection con = DriverManager.getConnection(url, username, password); + Statement st = con.createStatement();) { + + try (ResultSet rs = st.executeQuery("SELECT VERSION()")) { + if (rs.next()) { + logger.info("Connected to: " + rs.getString(1)); + } + } + + } catch (SQLException e) { + String msg = "Failed to open DB connection to URL {0} due to: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, url, e.getMessage()); + throw new StrolchConfigurationException(msg, e); + } + } + } + +} diff --git a/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java b/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java new file mode 100644 index 000000000..420f5d80f --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java @@ -0,0 +1,201 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Map; +import java.util.Properties; + +import li.strolch.exception.StrolchException; +import li.strolch.persistence.api.DbConnectionInfo; +import li.strolch.runtime.configuration.ComponentConfiguration; +import li.strolch.runtime.configuration.StrolchConfigurationException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ch.eitchnet.utils.dbc.DBC; +import ch.eitchnet.utils.helper.FileHelper; + +/** + * @author Robert von Burg + */ +@SuppressWarnings(value = "nls") +public class DbSchemaVersionCheck { + + private static final String RESOURCE_DB_VERSION = "/db_version.properties"; + private static final String PROP_DB_VERSION = "db_version"; + private static final String PROP_ALLOW_SCHEMA_CREATION = "allowSchemaCreation"; + private static final String PROP_ALLOW_SCHEMA_DROP = "allowSchemaDrop"; + + private static final Logger logger = LoggerFactory.getLogger(DbSchemaVersionCheck.class); + private Map connetionInfoMap; + private boolean allowSchemaCreation; + private boolean allowSchemaDrop; + + /** + * @param connetionInfoMap + * @param componentConfiguration + */ + public DbSchemaVersionCheck(Map connetionInfoMap, + ComponentConfiguration componentConfiguration) { + this.connetionInfoMap = connetionInfoMap; + + this.allowSchemaCreation = componentConfiguration.getBoolean(PROP_ALLOW_SCHEMA_CREATION, Boolean.FALSE); + this.allowSchemaDrop = componentConfiguration.getBoolean(PROP_ALLOW_SCHEMA_DROP, Boolean.FALSE); + } + + public void checkSchemaVersion() { + + Collection values = this.connetionInfoMap.values(); + + for (DbConnectionInfo connectionInfo : values) { + String realm = connectionInfo.getRealm(); + String url = connectionInfo.getUrl(); + String username = connectionInfo.getUsername(); + String password = connectionInfo.getPassword(); + + logger.info("Checking Schema version for realm " + realm + "..."); + + try (Connection con = DriverManager.getConnection(url, username, password); + Statement st = con.createStatement();) { + + String expectedDbVersion = getExpectedDbVersion(); + + // first see if we have any schema + String checkSchemaExistsSql = MessageFormat + .format("select table_schema, table_name, table_type from information_schema.tables where table_name=''{0}'';", + PROP_DB_VERSION); + try (ResultSet rs = st.executeQuery(checkSchemaExistsSql)) { + if (!rs.next()) { + createSchema(realm, expectedDbVersion, st); + } else { + checkCurrentVersion(realm, st, expectedDbVersion); + } + } + + } catch (SQLException e) { + String msg = "Failed to open DB connection to URL {0} due to: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, url, e.getMessage()); + throw new StrolchConfigurationException(msg, e); + } + } + } + + private void checkCurrentVersion(String realm, Statement st, String expectedDbVersion) throws SQLException { + try (ResultSet rs = st.executeQuery("select id, version from db_version order by id desc;")) { + if (!rs.next()) { + createSchema(realm, expectedDbVersion, st); + } else { + String currentVersion = rs.getString(2); + if (expectedDbVersion.equals(currentVersion)) { + logger.info("Schema version " + currentVersion + " is the current version. No changes needed."); + } else { + logger.warn("Schema version is not current. Need to upgrade from " + currentVersion + " to " + + expectedDbVersion); + upgradeSchema(realm, expectedDbVersion, st); + } + } + } + } + + private String getExpectedDbVersion() { + Properties dbVersionProps = new Properties(); + try (InputStream stream = getClass().getResourceAsStream(RESOURCE_DB_VERSION);) { + DBC.PRE.assertNotNull( + MessageFormat.format("Resource file with name {0} does not exist!", RESOURCE_DB_VERSION), stream); + dbVersionProps.load(stream); + } catch (IOException e) { + throw new StrolchException("Expected resource file " + RESOURCE_DB_VERSION + + " does not exist or is not a valid properties file: " + e.getMessage(), e); + } + String dbVersion = dbVersionProps.getProperty(PROP_DB_VERSION); + String msg = "Missing property {0} in resource file {1}"; + DBC.PRE.assertNotEmpty(MessageFormat.format(msg, PROP_DB_VERSION, RESOURCE_DB_VERSION), dbVersion); + return dbVersion; + } + + private String getSql(String dbVersion, String type) { + String schemaResourceS = "/db_schema_" + dbVersion + "_" + type + ".sql"; + try (InputStream stream = getClass().getResourceAsStream(schemaResourceS);) { + DBC.PRE.assertNotNull( + MessageFormat.format("Schema Resource file with name {0} does not exist!", schemaResourceS), stream); + return FileHelper.readStreamToString(stream); + } catch (IOException e) { + throw new StrolchException("Schema creation resource file is missing or could not be read: " + + schemaResourceS, e); + } + } + + /** + * @param realm + * @param st + */ + private void createSchema(String realm, String dbVersion, Statement st) { + + if (!this.allowSchemaCreation) { + throw new StrolchConfigurationException("[" + realm + + "] No schema exists, or is not valid. Schema generation is disabled, thus can not continue!"); + } + + logger.info("[" + realm + "] Creating initial schema..."); + + String sql = getSql(dbVersion, "initial"); + try { + st.execute(sql); + } catch (SQLException e) { + logger.error("Failed to execute schema creation SQL: \n" + sql); + throw new StrolchException("Failed to execute schema generation SQL: " + e.getMessage(), e); + } + + logger.info("[" + realm + "] Successfully created schema for version " + dbVersion); + } + + private void dropSchema(String realm, String dbVersion, Statement st) { + + if (!this.allowSchemaDrop) { + throw new StrolchConfigurationException("[" + realm + + "] Dropping Schema is disabled, but is required to upgrade current schema..."); + } + + logger.info("[" + realm + "] Dropping existing schema..."); + + String sql = getSql(dbVersion, "drop"); + try { + st.execute(sql); + } catch (SQLException e) { + logger.error("Failed to execute schema drop SQL: \n" + sql); + throw new StrolchException("Failed to execute schema drop SQL: " + e.getMessage(), e); + } + } + + /** + * @param st + */ + private void upgradeSchema(String realm, String dbVersion, Statement st) { + dropSchema(realm, dbVersion, st); + createSchema(realm, dbVersion, st); + } + +} diff --git a/src/main/java/li/strolch/persistence/postgresql/ModificationResult.java b/src/main/java/li/strolch/persistence/postgresql/ModificationResult.java new file mode 100644 index 000000000..21f272e54 --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/ModificationResult.java @@ -0,0 +1,60 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import java.util.ArrayList; +import java.util.List; + +public class ModificationResult { + + private final String key; + private final List created; + private final List updated; + private final List deleted; + + public ModificationResult(String key) { + this.key = key; + this.created = new ArrayList<>(); + this.updated = new ArrayList<>(); + this.deleted = new ArrayList<>(); + } + + public ModificationResult(String key, List created, List updated, List deleted) { + this.key = key; + this.created = created; + this.updated = updated; + this.deleted = deleted; + } + + public String getKey() { + return this.key; + } + + @SuppressWarnings("unchecked") + public List getCreated() { + return (List) this.created; + } + + @SuppressWarnings("unchecked") + public List getUpdated() { + return (List) this.updated; + } + + @SuppressWarnings("unchecked") + public List getDeleted() { + return (List) this.deleted; + } +} diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java new file mode 100644 index 000000000..93177fb58 --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java @@ -0,0 +1,33 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import li.strolch.model.Order; +import li.strolch.model.Tags; +import li.strolch.persistence.api.OrderDao; +import li.strolch.persistence.api.StrolchTransaction; + +public class PostgreSqlOrderDao extends AbstractDao implements OrderDao { + + protected PostgreSqlOrderDao(StrolchTransaction tx) { + super(tx); + } + + @Override + protected String getClassType() { + return Tags.ORDER; + } +} diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java new file mode 100644 index 000000000..e94245522 --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -0,0 +1,122 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +import li.strolch.persistence.api.DbConnectionInfo; +import li.strolch.persistence.api.OrderDao; +import li.strolch.persistence.api.ResourceDao; +import li.strolch.persistence.api.StrolchPersistenceHandler; +import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.runtime.component.ComponentContainer; +import li.strolch.runtime.component.StrolchComponent; +import li.strolch.runtime.configuration.ComponentConfiguration; +import li.strolch.runtime.configuration.StrolchConfigurationException; + +/** + * @author Robert von Burg + */ +public class PostgreSqlPersistenceHandler extends StrolchComponent implements StrolchPersistenceHandler { + + private static final String PROP_DB_URL = "db.url"; + private static final String PROP_DB_USERNAME = "db.username"; + private static final String PROP_DB_PASSWORD = "db.password"; + + private ComponentConfiguration componentConfiguration; + private Map connetionInfoMap; + + public PostgreSqlPersistenceHandler(ComponentContainer container, String componentName) { + super(container, componentName); + } + + @Override + public void initialize(ComponentConfiguration componentConfiguration) { + + this.componentConfiguration = componentConfiguration; + this.connetionInfoMap = new HashMap<>(); + + String dbUrl = componentConfiguration.getString(PROP_DB_URL, null); + String username = componentConfiguration.getString(PROP_DB_USERNAME, null); + String password = componentConfiguration.getString(PROP_DB_PASSWORD, null); + + Driver driver; + try { + driver = DriverManager.getDriver(dbUrl); + } catch (SQLException e) { + String msg = "Failed to load DB driver for URL {0} due to: {1}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, dbUrl, e.getMessage()); + throw new StrolchConfigurationException(msg, e); + } + + DbConnectionInfo connectionInfo = new DbConnectionInfo(StrolchTransaction.DEFAULT_REALM, dbUrl); + connectionInfo.setUsername(username); + connectionInfo.setPassword(password); + this.connetionInfoMap.put(StrolchTransaction.DEFAULT_REALM, connectionInfo); + + String compliant = driver.jdbcCompliant() ? "" : "non"; //$NON-NLS-1$ //$NON-NLS-2$ + String msg = "Using {0} JDBC compliant Driver {1}.{2}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, compliant, driver.getMajorVersion(), driver.getMinorVersion()); + logger.info(msg); + + super.initialize(componentConfiguration); + } + + @Override + public void start() { + + // test all connections + DbConnectionCheck connectionCheck = new DbConnectionCheck(this.connetionInfoMap); + connectionCheck.checkConnections(); + + DbSchemaVersionCheck schemaVersionCheck = new DbSchemaVersionCheck(this.connetionInfoMap, + componentConfiguration); + schemaVersionCheck.checkSchemaVersion(); + + super.start(); + } + + public StrolchTransaction openTx() { + return openTx(StrolchTransaction.DEFAULT_REALM); + } + + @SuppressWarnings("resource") + // caller will/must close + public StrolchTransaction openTx(String realm) { +// PersistenceTransaction tx = this.persistenceManager.openTx(realm); +// XmlStrolchTransaction strolchTx = new XmlStrolchTransaction(tx); +// if (getContainer().hasComponent(ObserverHandler.class)) { +// strolchTx.setObserverHandler(getContainer().getComponent(ObserverHandler.class)); +// } +// return strolchTx; + return null; + } + + @Override + public OrderDao getOrderDao(StrolchTransaction tx) { + return new PostgreSqlOrderDao(tx); + } + + @Override + public ResourceDao getResourceDao(StrolchTransaction tx) { + return new PostgreSqlResourceDao(tx); + } +} diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java new file mode 100644 index 000000000..eefe65b9d --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java @@ -0,0 +1,33 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import li.strolch.model.Resource; +import li.strolch.model.Tags; +import li.strolch.persistence.api.ResourceDao; +import li.strolch.persistence.api.StrolchTransaction; + +public class PostgreSqlResourceDao extends AbstractDao implements ResourceDao { + + protected PostgreSqlResourceDao(StrolchTransaction tx) { + super(tx); + } + + @Override + protected String getClassType() { + return Tags.RESOURCE; + } +} diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java new file mode 100644 index 000000000..a4b55b305 --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -0,0 +1,102 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import li.strolch.persistence.api.StrolchPersistenceException; +import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.persistence.api.TransactionCloseStrategy; +import li.strolch.runtime.observer.ObserverHandler; + +public class PostgreSqlStrolchTransaction implements StrolchTransaction { + + private ObserverHandler observerHandler; + private boolean suppressUpdates; + private TransactionCloseStrategy closeStrategy; +// private TransactionResult txResult; + + public PostgreSqlStrolchTransaction(/*PersistenceTransaction tx*/) { + this.suppressUpdates = false; +// this.tx = tx; + this.closeStrategy = TransactionCloseStrategy.COMMIT; + } + + /** + * @param observerHandler + * the observerHandler to set + */ + public void setObserverHandler(ObserverHandler observerHandler) { + this.observerHandler = observerHandler; + } + + /** + * @param suppressUpdates + * the suppressUpdates to set + */ + public void setSuppressUpdates(boolean suppressUpdates) { + this.suppressUpdates = suppressUpdates; + } + + /** + * @return the suppressUpdates + */ + public boolean isSuppressUpdates() { + return this.suppressUpdates; + } + + @Override + public void setCloseStrategy(TransactionCloseStrategy closeStrategy) { + this.closeStrategy = closeStrategy; + } + + @Override + public void autoCloseableCommit() { + + if (!this.suppressUpdates && this.observerHandler != null) { +// this.txResult = new TransactionResult(); +// this.tx.setTransactionResult(this.txResult); + } + +// this.tx.autoCloseableCommit(); + + if (!this.suppressUpdates && this.observerHandler != null) { + +// Set keys = this.txResult.getKeys(); +// for (String key : keys) { +// ModificationResult modificationResult = this.txResult.getModificationResult(key); +// +// this.observerHandler.add(key, modificationResult. getCreated()); +// this.observerHandler.update(key, modificationResult. getUpdated()); +// this.observerHandler.remove(key, modificationResult. getDeleted()); +// } + } + } + + @Override + public void autoCloseableRollback() { +// this.tx.autoCloseableRollback(); + } + + @Override + public void close() throws StrolchPersistenceException { + this.closeStrategy.close(this); + } + + @Override + public boolean isOpen() { +// return this.tx.isOpen(); + return true; + } +} diff --git a/src/main/resources/db_schema_0.1.0_drop.sql b/src/main/resources/db_schema_0.1.0_drop.sql new file mode 100644 index 000000000..fe35890fd --- /dev/null +++ b/src/main/resources/db_schema_0.1.0_drop.sql @@ -0,0 +1,5 @@ + +DROP TABLE IF EXISTS resources, orders, db_version; + +DROP TYPE IF EXISTS order_state; + diff --git a/src/main/resources/db_schema_0.1.0_initial.sql b/src/main/resources/db_schema_0.1.0_initial.sql new file mode 100644 index 000000000..808f6b97a --- /dev/null +++ b/src/main/resources/db_schema_0.1.0_initial.sql @@ -0,0 +1,33 @@ + +CREATE TABLE IF NOT EXISTS db_version ( + id SERIAL PRIMARY KEY, + version varchar(255), + description varchar(255), + created timestamp with time zone +); + +CREATE TABLE IF NOT EXISTS resources ( + id varchar(255) PRIMARY KEY, + name VARCHAR(255), + type VARCHAR(255), + asxml xml +); + +CREATE TYPE order_state AS ENUM ('CREATED', 'OPEN', 'EXECUTION', 'CLOSED'); + +CREATE TABLE IF NOT EXISTS orders ( + id varchar(255) PRIMARY KEY, + name VARCHAR(255), + type VARCHAR(255), + state order_state, + date timestamp with time zone, + asxml xml +); + +INSERT INTO db_version + (version, description, created) +values( + '0.1.0', + 'Initial schema version', + CURRENT_TIMESTAMP +); diff --git a/src/main/resources/db_version.properties b/src/main/resources/db_version.properties new file mode 100644 index 000000000..d0ef82ac6 --- /dev/null +++ b/src/main/resources/db_version.properties @@ -0,0 +1,2 @@ +# Property file defining what the currently expected version is supposed to be +db_version=0.1.0 \ No newline at end of file diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java new file mode 100644 index 000000000..612806108 --- /dev/null +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql.dao.test; + +import java.io.File; + +import li.strolch.persistence.api.StrolchPersistenceHandler; +import li.strolch.testbase.runtime.RuntimeMock; + +import org.junit.AfterClass; +import org.junit.BeforeClass; + +/** + * @author Robert von Burg + * + */ +public abstract class AbstractDaoImplTest extends RuntimeMock { + + private static final String RUNTIME_PATH = "target/strolchRuntime/"; //$NON-NLS-1$ + private static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ + private static final String CONFIG_SRC = "src/test/resources/runtime/config"; //$NON-NLS-1$ + protected static StrolchPersistenceHandler persistenceHandler; + + @BeforeClass + public static void beforeClass() { + + File rootPath = new File(RUNTIME_PATH); + File configSrc = new File(CONFIG_SRC); + RuntimeMock.mockRuntime(rootPath, configSrc); + new File(rootPath, DB_STORE_PATH_DIR).mkdir(); + RuntimeMock.startContainer(rootPath); + + // initialize the component configuration + persistenceHandler = getContainer().getComponent(StrolchPersistenceHandler.class); + } + + @AfterClass + public static void afterClass() { + RuntimeMock.destroyRuntime(); + } +} diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java new file mode 100644 index 000000000..a5dc772aa --- /dev/null +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -0,0 +1,98 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql.dao.test; + +import static li.strolch.model.ModelGenerator.createOrder; +import static li.strolch.model.ModelGenerator.createResource; +import static org.junit.Assert.assertEquals; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import li.strolch.model.Order; +import li.strolch.model.Resource; +import li.strolch.model.State; +import li.strolch.model.StrolchElement; +import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.persistence.postgresql.ModificationResult; +import li.strolch.runtime.observer.Observer; +import li.strolch.runtime.observer.ObserverHandler; + +import org.junit.Test; + +/** + * @author Robert von Burg + * + */ +public class ObserverUpdateTest extends AbstractDaoImplTest { + + public final class ElementAddedObserver implements Observer { + + Map results = new HashMap<>(); + + private ModificationResult getModificationResult(String key) { + ModificationResult result = this.results.get(key); + if (result == null) { + result = new ModificationResult(key); + this.results.put(key, result); + } + return result; + } + + @Override + public void update(String key, List elements) { + getModificationResult(key).getUpdated().addAll(elements); + } + + @Override + public void remove(String key, List elements) { + getModificationResult(key).getDeleted().addAll(elements); + } + + @Override + public void add(String key, List elements) { + getModificationResult(key).getCreated().addAll(elements); + } + } + + @Test + public void shouldReceiveUpdates() { + + // register an observer for orders and resources + ElementAddedObserver observer = new ElementAddedObserver(); + getContainer().getComponent(ObserverHandler.class).registerObserver("Order", observer); //$NON-NLS-1$ + getContainer().getComponent(ObserverHandler.class).registerObserver("Resource", observer); //$NON-NLS-1$ + + // create order + Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType", new Date(), State.CREATED); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + try (StrolchTransaction tx = persistenceHandler.openTx();) { + persistenceHandler.getOrderDao(tx).save(newOrder); + } + + // create resource + Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + try (StrolchTransaction tx = persistenceHandler.openTx();) { + persistenceHandler.getResourceDao(tx).save(newResource); + } + + assertEquals(2, observer.results.size()); + assertEquals(1, observer.results.get("Order").getCreated().size()); //$NON-NLS-1$ + assertEquals(1, observer.results.get("Resource").getCreated().size()); //$NON-NLS-1$ + + } +} diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java new file mode 100644 index 000000000..205f3bd69 --- /dev/null +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java @@ -0,0 +1,92 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql.dao.test; + +import static li.strolch.model.ModelGenerator.BAG_ID; +import static li.strolch.model.ModelGenerator.PARAM_STRING_ID; +import static li.strolch.model.ModelGenerator.createOrder; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import li.strolch.model.Order; +import li.strolch.model.parameter.Parameter; +import li.strolch.persistence.api.StrolchTransaction; + +import org.junit.Test; + +public class PostgreSqlOrderDaoTest extends AbstractDaoImplTest { + + private static final String ID = "@testOrder"; //$NON-NLS-1$ + private static final String NAME = "Test Order"; //$NON-NLS-1$ + private static final String TYPE = "ToStock"; //$NON-NLS-1$ + + @Test + public void shouldCreateOrder() { + + // create + Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + try (StrolchTransaction tx = persistenceHandler.openTx();) { + persistenceHandler.getOrderDao(tx).save(newOrder); + } + } + + @Test + public void shouldCrud() { + + // create + Order newOrder = createOrder(ID, NAME, TYPE); + try (StrolchTransaction tx = persistenceHandler.openTx();) { + persistenceHandler.getOrderDao(tx).save(newOrder); + } + + // read + Order readOrder = null; + try (StrolchTransaction tx = persistenceHandler.openTx();) { + readOrder = persistenceHandler.getOrderDao(tx).queryBy(TYPE, ID); + } + assertNotNull("Should read Order with id " + ID, readOrder); //$NON-NLS-1$ + + // update + Parameter sParam = readOrder.getParameter(BAG_ID, PARAM_STRING_ID); + String newStringValue = "Giddiya!"; //$NON-NLS-1$ + sParam.setValue(newStringValue); + try (StrolchTransaction tx = persistenceHandler.openTx();) { + persistenceHandler.getOrderDao(tx).update(readOrder); + } + + // read updated + Order updatedOrder = null; + try (StrolchTransaction tx = persistenceHandler.openTx();) { + updatedOrder = persistenceHandler.getOrderDao(tx).queryBy(TYPE, ID); + } + assertNotNull("Should read Order with id " + ID, updatedOrder); //$NON-NLS-1$ + assertFalse("Objects can't be the same reference after re-reading!", readOrder == updatedOrder); //$NON-NLS-1$ + Parameter updatedParam = readOrder.getParameter(BAG_ID, PARAM_STRING_ID); + assertEquals(newStringValue, updatedParam.getValue()); + + // delete + try (StrolchTransaction tx = persistenceHandler.openTx();) { + persistenceHandler.getOrderDao(tx).remove(readOrder); + } + + // fail to re-read + try (StrolchTransaction tx = persistenceHandler.openTx();) { + Order order = persistenceHandler.getOrderDao(tx).queryBy(TYPE, ID); + assertNull("Should no read Order with id " + ID, order); //$NON-NLS-1$ + } + } +} diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java new file mode 100644 index 000000000..f1154a1e2 --- /dev/null +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java @@ -0,0 +1,92 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql.dao.test; + +import static li.strolch.model.ModelGenerator.BAG_ID; +import static li.strolch.model.ModelGenerator.PARAM_STRING_ID; +import static li.strolch.model.ModelGenerator.createResource; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import li.strolch.model.Resource; +import li.strolch.model.parameter.Parameter; +import li.strolch.persistence.api.StrolchTransaction; + +import org.junit.Test; + +public class PostgreSqlResourceDaoTest extends AbstractDaoImplTest { + + private static final String ID = "@testResource"; //$NON-NLS-1$ + private static final String NAME = "Test Resource"; //$NON-NLS-1$ + private static final String TYPE = "Box"; //$NON-NLS-1$ + + @Test + public void shouldCreateResource() { + + // create + Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + try (StrolchTransaction tx = persistenceHandler.openTx();) { + persistenceHandler.getResourceDao(tx).save(newResource); + } + } + + @Test + public void shouldCrud() { + + // create + Resource newResource = createResource(ID, NAME, TYPE); + try (StrolchTransaction tx = persistenceHandler.openTx();) { + persistenceHandler.getResourceDao(tx).save(newResource); + } + + // read + Resource readResource = null; + try (StrolchTransaction tx = persistenceHandler.openTx();) { + readResource = persistenceHandler.getResourceDao(tx).queryBy(TYPE, ID); + } + assertNotNull("Should read Resource with id " + ID, readResource); //$NON-NLS-1$ + + // update + Parameter sParam = readResource.getParameter(BAG_ID, PARAM_STRING_ID); + String newStringValue = "Giddiya!"; //$NON-NLS-1$ + sParam.setValue(newStringValue); + try (StrolchTransaction tx = persistenceHandler.openTx();) { + persistenceHandler.getResourceDao(tx).update(readResource); + } + + // read updated + Resource updatedResource = null; + try (StrolchTransaction tx = persistenceHandler.openTx();) { + updatedResource = persistenceHandler.getResourceDao(tx).queryBy(TYPE, ID); + } + assertNotNull("Should read Resource with id " + ID, updatedResource); //$NON-NLS-1$ + assertFalse("Objects can't be the same reference after re-reading!", readResource == updatedResource); //$NON-NLS-1$ + Parameter updatedParam = readResource.getParameter(BAG_ID, PARAM_STRING_ID); + assertEquals(newStringValue, updatedParam.getValue()); + + // delete + try (StrolchTransaction tx = persistenceHandler.openTx();) { + persistenceHandler.getResourceDao(tx).remove(readResource); + } + + // fail to re-read + try (StrolchTransaction tx = persistenceHandler.openTx();) { + Resource resource = persistenceHandler.getResourceDao(tx).queryBy(TYPE, ID); + assertNull("Should no read Resource with id " + ID, resource); //$NON-NLS-1$ + } + } +} diff --git a/src/test/resources/log4j.xml b/src/test/resources/log4j.xml new file mode 100644 index 000000000..a35a3c351 --- /dev/null +++ b/src/test/resources/log4j.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/runtime/config/StrolchConfiguration.xml b/src/test/resources/runtime/config/StrolchConfiguration.xml new file mode 100644 index 000000000..26f7d59b0 --- /dev/null +++ b/src/test/resources/runtime/config/StrolchConfiguration.xml @@ -0,0 +1,27 @@ + + + + StrolchPersistenceTest + + EMPTY + true + + + + PersistenceHandler + li.strolch.persistence.api.StrolchPersistenceHandler + li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler + + true + true + jdbc:postgresql://localhost/testdb + testuser + test + + + + ObserverHandler + li.strolch.runtime.observer.ObserverHandler + li.strolch.runtime.observer.DefaultObserverHandler + + \ No newline at end of file From 29527a2496dcb6d4a8f26a24bc77f0f14545d8ed Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 23 Dec 2013 01:55:34 +0100 Subject: [PATCH 03/61] [New] Implemented a basic PostgreSQL for Resources and Orders --- .../persistence/postgresql/AbstractDao.java | 96 ------ .../persistence/postgresql/DaoCommand.java | 26 ++ .../postgresql/DbConnectionCheck.java | 6 +- .../postgresql/DbSchemaVersionCheck.java | 8 +- .../postgresql/ModificationResult.java | 60 ---- .../postgresql/PostgreSqlOrderDao.java | 121 +++++++- .../PostgreSqlPersistenceHandler.java | 46 ++- .../postgresql/PostgreSqlResourceDao.java | 108 ++++++- .../PostgreSqlStrolchTransaction.java | 142 +++++++-- .../persistence/postgresql/PostgresqlDao.java | 283 ++++++++++++++++++ .../dao/test/AbstractDaoImplTest.java | 19 +- .../dao/test/ObserverUpdateTest.java | 12 +- 12 files changed, 713 insertions(+), 214 deletions(-) delete mode 100644 src/main/java/li/strolch/persistence/postgresql/AbstractDao.java create mode 100644 src/main/java/li/strolch/persistence/postgresql/DaoCommand.java delete mode 100644 src/main/java/li/strolch/persistence/postgresql/ModificationResult.java create mode 100644 src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java diff --git a/src/main/java/li/strolch/persistence/postgresql/AbstractDao.java b/src/main/java/li/strolch/persistence/postgresql/AbstractDao.java deleted file mode 100644 index 16b474dc8..000000000 --- a/src/main/java/li/strolch/persistence/postgresql/AbstractDao.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2013 Robert von Burg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package li.strolch.persistence.postgresql; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import li.strolch.model.StrolchElement; -import li.strolch.persistence.api.StrolchDao; -import li.strolch.persistence.api.StrolchTransaction; - -public abstract class AbstractDao implements StrolchDao { - - protected AbstractDao(StrolchTransaction tx) { - PostgreSqlStrolchTransaction strolchTx = (PostgreSqlStrolchTransaction) tx; - } - - protected abstract String getClassType(); - - @Override - public Set queryKeySet() { - Set keys = new HashSet<>(); - Set types = queryTypes(); - for (String type : types) { - keys.addAll(queryKeySet(type)); - } - return keys; - } - - @Override - public Set queryKeySet(String type) { - return null; - } - - @Override - public Set queryTypes() { - return null; - } - - @Override - public T queryBy(String type, String id) { - return null; - } - - @Override - public List queryAll() { - return null; - } - - @Override - public List queryAll(String type) { - return null; - } - - @Override - public void save(T object) { - } - - @Override - public void saveAll(List objects) { - } - - @Override - public void update(T object) { - } - - @Override - public void updateAll(List objects) { - } - - @Override - public void remove(T object) { - } - - @Override - public void removeAll(List objects) { - } - - @Override - public void remove(String type, String id) { - } -} diff --git a/src/main/java/li/strolch/persistence/postgresql/DaoCommand.java b/src/main/java/li/strolch/persistence/postgresql/DaoCommand.java new file mode 100644 index 000000000..403684380 --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/DaoCommand.java @@ -0,0 +1,26 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import li.strolch.persistence.api.ModificationResult; + +/** + * @author Robert von Burg + */ +public interface DaoCommand { + + public void doComand(ModificationResult modificationResult); +} diff --git a/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java b/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java index bf8263721..ee8f5f16e 100644 --- a/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java +++ b/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java @@ -32,7 +32,6 @@ import li.strolch.runtime.configuration.StrolchConfigurationException; /** * @author Robert von Burg - * */ public class DbConnectionCheck { @@ -56,9 +55,9 @@ public class DbConnectionCheck { try (Connection con = DriverManager.getConnection(url, username, password); Statement st = con.createStatement();) { - try (ResultSet rs = st.executeQuery("SELECT VERSION()")) { + try (ResultSet rs = st.executeQuery("select version()")) { //$NON-NLS-1$ if (rs.next()) { - logger.info("Connected to: " + rs.getString(1)); + logger.info(MessageFormat.format("Connected to: {0}", rs.getString(1))); //$NON-NLS-1$ } } @@ -69,5 +68,4 @@ public class DbConnectionCheck { } } } - } diff --git a/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java b/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java index 420f5d80f..29242d65f 100644 --- a/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java +++ b/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java @@ -120,9 +120,9 @@ public class DbSchemaVersionCheck { } } - private String getExpectedDbVersion() { + public static String getExpectedDbVersion() { Properties dbVersionProps = new Properties(); - try (InputStream stream = getClass().getResourceAsStream(RESOURCE_DB_VERSION);) { + try (InputStream stream = DbSchemaVersionCheck.class.getResourceAsStream(RESOURCE_DB_VERSION);) { DBC.PRE.assertNotNull( MessageFormat.format("Resource file with name {0} does not exist!", RESOURCE_DB_VERSION), stream); dbVersionProps.load(stream); @@ -136,9 +136,9 @@ public class DbSchemaVersionCheck { return dbVersion; } - private String getSql(String dbVersion, String type) { + public static String getSql(String dbVersion, String type) { String schemaResourceS = "/db_schema_" + dbVersion + "_" + type + ".sql"; - try (InputStream stream = getClass().getResourceAsStream(schemaResourceS);) { + try (InputStream stream = DbSchemaVersionCheck.class.getResourceAsStream(schemaResourceS);) { DBC.PRE.assertNotNull( MessageFormat.format("Schema Resource file with name {0} does not exist!", schemaResourceS), stream); return FileHelper.readStreamToString(stream); diff --git a/src/main/java/li/strolch/persistence/postgresql/ModificationResult.java b/src/main/java/li/strolch/persistence/postgresql/ModificationResult.java deleted file mode 100644 index 21f272e54..000000000 --- a/src/main/java/li/strolch/persistence/postgresql/ModificationResult.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013 Robert von Burg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package li.strolch.persistence.postgresql; - -import java.util.ArrayList; -import java.util.List; - -public class ModificationResult { - - private final String key; - private final List created; - private final List updated; - private final List deleted; - - public ModificationResult(String key) { - this.key = key; - this.created = new ArrayList<>(); - this.updated = new ArrayList<>(); - this.deleted = new ArrayList<>(); - } - - public ModificationResult(String key, List created, List updated, List deleted) { - this.key = key; - this.created = created; - this.updated = updated; - this.deleted = deleted; - } - - public String getKey() { - return this.key; - } - - @SuppressWarnings("unchecked") - public List getCreated() { - return (List) this.created; - } - - @SuppressWarnings("unchecked") - public List getUpdated() { - return (List) this.updated; - } - - @SuppressWarnings("unchecked") - public List getDeleted() { - return (List) this.deleted; - } -} diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java index 93177fb58..6a8ac1a65 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java @@ -9,25 +9,136 @@ * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either exporders or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package li.strolch.persistence.postgresql; +import java.io.IOException; +import java.io.InputStream; +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.SQLXML; +import java.text.MessageFormat; +import java.util.Calendar; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.sax.SAXResult; + import li.strolch.model.Order; import li.strolch.model.Tags; +import li.strolch.model.xml.OrderToSaxVisitor; +import li.strolch.model.xml.SimpleStrolchElementListener; +import li.strolch.model.xml.XmlModelDefaultHandler; import li.strolch.persistence.api.OrderDao; -import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.persistence.api.StrolchPersistenceException; -public class PostgreSqlOrderDao extends AbstractDao implements OrderDao { +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; - protected PostgreSqlOrderDao(StrolchTransaction tx) { +@SuppressWarnings("nls") +public class PostgreSqlOrderDao extends PostgresqlDao implements OrderDao { + + /** + * @param tx + */ + public PostgreSqlOrderDao(PostgreSqlStrolchTransaction tx) { super(tx); } @Override - protected String getClassType() { + protected String getClassName() { return Tags.ORDER; } + + @Override + protected String getTableName() { + return "orders"; + } + + @Override + protected Order parseFromXml(String id, String type, SQLXML sqlxml) { + SimpleStrolchElementListener listener = new SimpleStrolchElementListener(); + try (InputStream binaryStream = sqlxml.getBinaryStream()) { + SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); + parser.parse(binaryStream, new XmlModelDefaultHandler(listener)); + } catch (SQLException | IOException | SAXException | ParserConfigurationException e) { + throw new StrolchPersistenceException(MessageFormat.format( + "Failed to extract Order from sqlxml value for {0} / {1}", id, type)); + } + + if (listener.getOrders().size() == 0) + throw new StrolchPersistenceException(MessageFormat.format( + "No Orders parsed from sqlxml value for {0} / {1}", id, type)); + if (listener.getOrders().size() > 1) + throw new StrolchPersistenceException(MessageFormat.format( + "Multiple Orders parsed from sqlxml value for {0} / {1}", id, type)); + + return listener.getOrders().get(0); + } + + protected SQLXML createSqlXml(Order order, PreparedStatement preparedStatement) throws SQLException, SAXException { + SQLXML sqlxml = this.tx.getConnection().createSQLXML(); + SAXResult saxResult = sqlxml.setResult(SAXResult.class); + ContentHandler contentHandler = saxResult.getHandler(); + contentHandler.startDocument(); + new OrderToSaxVisitor(contentHandler).visit(order); + contentHandler.endDocument(); + return sqlxml; + } + + @Override + protected void internalSave(final Order order) { + String sql = "insert into " + getTableName() + + " (id, name, type, state, date, asxml) values (?, ?, ?, ?::order_state, ?, ?)"; + try (PreparedStatement preparedStatement = PostgreSqlOrderDao.this.tx.getConnection().prepareStatement(sql)) { + preparedStatement.setString(1, order.getId()); + preparedStatement.setString(2, order.getName()); + preparedStatement.setString(3, order.getType()); + preparedStatement.setString(4, order.getState().name()); + preparedStatement.setDate(5, new Date(order.getDate().getTime()), Calendar.getInstance()); + + SQLXML sqlxml = createSqlXml(order, preparedStatement); + preparedStatement.setSQLXML(6, sqlxml); + try { + preparedStatement.execute(); + } finally { + sqlxml.free(); + } + + } catch (SQLException | SAXException e) { + throw new StrolchPersistenceException(MessageFormat.format("Failed to insert Order {0} due to {1}", + order.getLocator(), e.getLocalizedMessage()), e); + } + } + + @Override + protected void internalUpdate(final Order order) { + String sql = "update " + getTableName() + + " set name = ?, type = ?, state = ?::order_state, date = ?, asxml = ? where id = ? "; + try (PreparedStatement preparedStatement = PostgreSqlOrderDao.this.tx.getConnection().prepareStatement(sql)) { + + preparedStatement.setString(1, order.getName()); + preparedStatement.setString(2, order.getType()); + preparedStatement.setString(3, order.getState().name()); + preparedStatement.setDate(4, new Date(order.getDate().getTime()), Calendar.getInstance()); + preparedStatement.setString(6, order.getId()); + + SQLXML sqlxml = createSqlXml(order, preparedStatement); + preparedStatement.setSQLXML(5, sqlxml); + try { + preparedStatement.execute(); + } finally { + sqlxml.free(); + } + + } catch (SQLException | SAXException e) { + throw new StrolchPersistenceException(MessageFormat.format("Failed to update Order {0} due to {1}", + order.getLocator(), e.getLocalizedMessage()), e); + } + } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index e94245522..e674844c5 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -15,6 +15,7 @@ */ package li.strolch.persistence.postgresql; +import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; @@ -25,21 +26,23 @@ import java.util.Map; import li.strolch.persistence.api.DbConnectionInfo; import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.ResourceDao; +import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.StrolchPersistenceHandler; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.runtime.component.ComponentContainer; import li.strolch.runtime.component.StrolchComponent; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.StrolchConfigurationException; +import li.strolch.runtime.observer.ObserverHandler; /** * @author Robert von Burg */ public class PostgreSqlPersistenceHandler extends StrolchComponent implements StrolchPersistenceHandler { - private static final String PROP_DB_URL = "db.url"; - private static final String PROP_DB_USERNAME = "db.username"; - private static final String PROP_DB_PASSWORD = "db.password"; + private static final String PROP_DB_URL = "db.url"; //$NON-NLS-1$ + private static final String PROP_DB_USERNAME = "db.username"; //$NON-NLS-1$ + private static final String PROP_DB_PASSWORD = "db.password"; //$NON-NLS-1$ private ComponentConfiguration componentConfiguration; private Map connetionInfoMap; @@ -88,7 +91,7 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements St connectionCheck.checkConnections(); DbSchemaVersionCheck schemaVersionCheck = new DbSchemaVersionCheck(this.connetionInfoMap, - componentConfiguration); + this.componentConfiguration); schemaVersionCheck.checkSchemaVersion(); super.start(); @@ -98,25 +101,38 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements St return openTx(StrolchTransaction.DEFAULT_REALM); } - @SuppressWarnings("resource") - // caller will/must close public StrolchTransaction openTx(String realm) { -// PersistenceTransaction tx = this.persistenceManager.openTx(realm); -// XmlStrolchTransaction strolchTx = new XmlStrolchTransaction(tx); -// if (getContainer().hasComponent(ObserverHandler.class)) { -// strolchTx.setObserverHandler(getContainer().getComponent(ObserverHandler.class)); -// } -// return strolchTx; - return null; + PostgreSqlStrolchTransaction tx = new PostgreSqlStrolchTransaction(realm, this); + if (getContainer().hasComponent(ObserverHandler.class)) { + tx.setObserverHandler(getContainer().getComponent(ObserverHandler.class)); + } + return tx; } @Override public OrderDao getOrderDao(StrolchTransaction tx) { - return new PostgreSqlOrderDao(tx); + PostgreSqlStrolchTransaction sqlTx = (PostgreSqlStrolchTransaction) tx; + return sqlTx.getOrderDao(sqlTx); } @Override public ResourceDao getResourceDao(StrolchTransaction tx) { - return new PostgreSqlResourceDao(tx); + PostgreSqlStrolchTransaction sqlTx = (PostgreSqlStrolchTransaction) tx; + return sqlTx.getResourceDao(sqlTx); + } + + Connection getConnection(String realm) { + DbConnectionInfo dbInfo = this.connetionInfoMap.get(realm); + if (dbInfo == null) { + String msg = MessageFormat.format("There is no connection registered for the realm {0}", realm); //$NON-NLS-1$ + throw new StrolchPersistenceException(msg); + } + + try { + return DriverManager.getConnection(dbInfo.getUrl(), dbInfo.getUsername(), dbInfo.getPassword()); + } catch (SQLException e) { + String msg = MessageFormat.format("Failed to get a connection for {0} due to {1}", dbInfo, e.getMessage()); //$NON-NLS-1$ + throw new StrolchPersistenceException(msg, e); + } } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java index eefe65b9d..6b4c0b98d 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java @@ -15,19 +15,119 @@ */ package li.strolch.persistence.postgresql; +import java.io.IOException; +import java.io.InputStream; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.SQLXML; +import java.text.MessageFormat; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.sax.SAXResult; + import li.strolch.model.Resource; import li.strolch.model.Tags; +import li.strolch.model.xml.ResourceToSaxVisitor; +import li.strolch.model.xml.SimpleStrolchElementListener; +import li.strolch.model.xml.XmlModelDefaultHandler; import li.strolch.persistence.api.ResourceDao; -import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.persistence.api.StrolchPersistenceException; -public class PostgreSqlResourceDao extends AbstractDao implements ResourceDao { +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; - protected PostgreSqlResourceDao(StrolchTransaction tx) { +@SuppressWarnings("nls") +public class PostgreSqlResourceDao extends PostgresqlDao implements ResourceDao { + + protected PostgreSqlResourceDao(PostgreSqlStrolchTransaction tx) { super(tx); } @Override - protected String getClassType() { + protected String getClassName() { return Tags.RESOURCE; } + + @Override + protected String getTableName() { + return "resources"; + } + + @Override + protected Resource parseFromXml(String id, String type, SQLXML sqlxml) { + SimpleStrolchElementListener listener = new SimpleStrolchElementListener(); + try (InputStream binaryStream = sqlxml.getBinaryStream()) { + SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); + parser.parse(binaryStream, new XmlModelDefaultHandler(listener)); + } catch (SQLException | IOException | SAXException | ParserConfigurationException e) { + throw new StrolchPersistenceException(MessageFormat.format( + "Failed to extract Resource from sqlxml value for {0} / {1}", id, type)); + } + + if (listener.getResources().size() == 0) + throw new StrolchPersistenceException(MessageFormat.format( + "No Resource parsed from sqlxml value for {0} / {1}", id, type)); + if (listener.getResources().size() > 1) + throw new StrolchPersistenceException(MessageFormat.format( + "Multiple Resources parsed from sqlxml value for {0} / {1}", id, type)); + + return listener.getResources().get(0); + } + + protected SQLXML createSqlXml(Resource res, PreparedStatement preparedStatement) throws SQLException, SAXException { + SQLXML sqlxml = this.tx.getConnection().createSQLXML(); + SAXResult saxResult = sqlxml.setResult(SAXResult.class); + ContentHandler contentHandler = saxResult.getHandler(); + contentHandler.startDocument(); + new ResourceToSaxVisitor(contentHandler).visit(res); + contentHandler.endDocument(); + return sqlxml; + } + + @Override + protected void internalSave(final Resource res) { + String sql = "insert into " + getTableName() + " (id, name, type, asxml) values (?, ?, ?, ?)"; + try (PreparedStatement preparedStatement = PostgreSqlResourceDao.this.tx.getConnection().prepareStatement(sql)) { + preparedStatement.setString(1, res.getId()); + preparedStatement.setString(2, res.getName()); + preparedStatement.setString(3, res.getType()); + + SQLXML sqlxml = createSqlXml(res, preparedStatement); + preparedStatement.setSQLXML(4, sqlxml); + try { + preparedStatement.execute(); + } finally { + sqlxml.free(); + } + + } catch (SQLException | SAXException e) { + throw new StrolchPersistenceException(MessageFormat.format("Failed to insert Resource {0} due to {1}", + res.getLocator(), e.getLocalizedMessage()), e); + } + } + + @Override + protected void internalUpdate(final Resource resource) { + String sql = "update " + getTableName() + " set name = ?, type = ?, asxml = ? where id = ? "; + try (PreparedStatement preparedStatement = PostgreSqlResourceDao.this.tx.getConnection().prepareStatement(sql)) { + + preparedStatement.setString(1, resource.getName()); + preparedStatement.setString(2, resource.getType()); + preparedStatement.setString(4, resource.getId()); + + SQLXML sqlxml = createSqlXml(resource, preparedStatement); + preparedStatement.setSQLXML(3, sqlxml); + try { + preparedStatement.execute(); + } finally { + sqlxml.free(); + } + + } catch (SQLException | SAXException e) { + throw new StrolchPersistenceException(MessageFormat.format("Failed to update Resource {0} due to {1}", + resource.getLocator(), e.getLocalizedMessage()), e); + } + } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index a4b55b305..dc74d3bcb 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -15,21 +15,50 @@ */ package li.strolch.persistence.postgresql; +import java.sql.Connection; +import java.util.Date; +import java.util.Set; + +import li.strolch.model.StrolchElement; +import li.strolch.persistence.api.ModificationResult; +import li.strolch.persistence.api.OrderDao; +import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.api.TransactionCloseStrategy; +import li.strolch.persistence.api.TransactionResult; +import li.strolch.persistence.api.TransactionState; import li.strolch.runtime.observer.ObserverHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ch.eitchnet.utils.helper.StringHelper; + public class PostgreSqlStrolchTransaction implements StrolchTransaction { + private static final Logger logger = LoggerFactory.getLogger(PostgreSqlStrolchTransaction.class); + private PostgreSqlPersistenceHandler persistenceHandler; + private String realm; + + private TransactionCloseStrategy closeStrategy; private ObserverHandler observerHandler; private boolean suppressUpdates; - private TransactionCloseStrategy closeStrategy; -// private TransactionResult txResult; - public PostgreSqlStrolchTransaction(/*PersistenceTransaction tx*/) { + private PostgresqlDao orderDao; + private PostgresqlDao resourceDao; + private Connection connection; + private long startTime; + private Date startTimeDate; + private TransactionResult txResult; + private boolean open; + + public PostgreSqlStrolchTransaction(String realm, PostgreSqlPersistenceHandler persistenceHandler) { + this.startTime = System.nanoTime(); + this.startTimeDate = new Date(); + this.realm = realm; + this.persistenceHandler = persistenceHandler; this.suppressUpdates = false; -// this.tx = tx; this.closeStrategy = TransactionCloseStrategy.COMMIT; } @@ -64,29 +93,83 @@ public class PostgreSqlStrolchTransaction implements StrolchTransaction { @Override public void autoCloseableCommit() { - if (!this.suppressUpdates && this.observerHandler != null) { -// this.txResult = new TransactionResult(); -// this.tx.setTransactionResult(this.txResult); + if (logger.isDebugEnabled()) { + logger.info("Committing TX..."); //$NON-NLS-1$ } -// this.tx.autoCloseableCommit(); + long start = System.nanoTime(); + this.txResult = new TransactionResult(); + + try { + if (this.orderDao != null) { + this.orderDao.commit(this.txResult); + } + + if (this.resourceDao != null) { + this.resourceDao.commit(this.txResult); + } + + this.txResult.setState(TransactionState.COMMITTED); + + } catch (Exception e) { + this.txResult.setState(TransactionState.FAILED); + + long end = System.nanoTime(); + long txDuration = end - this.startTime; + long closeDuration = end - start; + StringBuilder sb = new StringBuilder(); + sb.append("TX has failed after "); //$NON-NLS-1$ + sb.append(StringHelper.formatNanoDuration(txDuration)); + sb.append(" with close operation taking "); //$NON-NLS-1$ + sb.append(StringHelper.formatNanoDuration(closeDuration)); + logger.info(sb.toString()); + + throw e; + } + + long end = System.nanoTime(); + long txDuration = end - this.startTime; + long closeDuration = end - start; + + this.txResult.setStartTime(this.startTimeDate); + this.txResult.setTxDuration(txDuration); + this.txResult.setCloseDuration(closeDuration); + this.txResult.setRealm(this.realm); + + StringBuilder sb = new StringBuilder(); + sb.append("TX was completed after "); //$NON-NLS-1$ + sb.append(StringHelper.formatNanoDuration(txDuration)); + sb.append(" with close operation taking "); //$NON-NLS-1$ + sb.append(StringHelper.formatNanoDuration(closeDuration)); + logger.info(sb.toString()); if (!this.suppressUpdates && this.observerHandler != null) { -// Set keys = this.txResult.getKeys(); -// for (String key : keys) { -// ModificationResult modificationResult = this.txResult.getModificationResult(key); -// -// this.observerHandler.add(key, modificationResult. getCreated()); -// this.observerHandler.update(key, modificationResult. getUpdated()); -// this.observerHandler.remove(key, modificationResult. getDeleted()); -// } + Set keys = this.txResult.getKeys(); + for (String key : keys) { + ModificationResult modificationResult = this.txResult.getModificationResult(key); + + this.observerHandler.add(key, modificationResult. getCreated()); + this.observerHandler.update(key, modificationResult. getUpdated()); + this.observerHandler.remove(key, modificationResult. getDeleted()); + } } } @Override public void autoCloseableRollback() { -// this.tx.autoCloseableRollback(); + long start = System.nanoTime(); + + long end = System.nanoTime(); + long txDuration = end - this.startTime; + long closeDuration = end - start; + + this.txResult = new TransactionResult(); + this.txResult.setState(TransactionState.ROLLED_BACK); + this.txResult.setStartTime(this.startTimeDate); + this.txResult.setTxDuration(txDuration); + this.txResult.setCloseDuration(closeDuration); + this.txResult.setRealm(this.realm); } @Override @@ -96,7 +179,28 @@ public class PostgreSqlStrolchTransaction implements StrolchTransaction { @Override public boolean isOpen() { -// return this.tx.isOpen(); - return true; + return this.open; + } + + OrderDao getOrderDao(PostgreSqlStrolchTransaction tx) { + if (this.orderDao == null) + this.orderDao = new PostgreSqlOrderDao(tx); + return (OrderDao) this.orderDao; + } + + ResourceDao getResourceDao(PostgreSqlStrolchTransaction tx) { + if (this.resourceDao == null) + this.resourceDao = new PostgreSqlResourceDao(tx); + return (ResourceDao) this.resourceDao; + } + + /** + * @return + */ + Connection getConnection() { + if (this.connection == null) { + this.connection = this.persistenceHandler.getConnection(this.realm); + } + return this.connection; } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java new file mode 100644 index 000000000..68a803523 --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java @@ -0,0 +1,283 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.SQLXML; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import li.strolch.model.StrolchElement; +import li.strolch.persistence.api.ModificationResult; +import li.strolch.persistence.api.StrolchDao; +import li.strolch.persistence.api.StrolchPersistenceException; +import li.strolch.persistence.api.TransactionResult; + +@SuppressWarnings("nls") +public abstract class PostgresqlDao implements StrolchDao { + + protected PostgreSqlStrolchTransaction tx; + protected List commands; + + /** + * @param tx + */ + public PostgresqlDao(PostgreSqlStrolchTransaction tx) { + this.tx = tx; + this.commands = new ArrayList<>(); + } + + protected abstract String getClassName(); + + protected abstract String getTableName(); + + protected abstract T parseFromXml(String id, String type, SQLXML xml); + + @Override + public Set queryKeySet() { + + Set keySet = new HashSet<>(); + + String sql = "select id from " + getTableName(); + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + try (ResultSet result = statement.executeQuery()) { + while (result.next()) { + keySet.add(result.getString("id")); + } + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query key set due to: " + e.getMessage(), e); + } + + return keySet; + } + + @Override + public Set queryKeySet(String type) { + Set keySet = new HashSet<>(); + + String sql = "select id from " + getTableName() + " where type = ?"; + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + statement.setString(1, type); + try (ResultSet result = statement.executeQuery()) { + while (result.next()) { + keySet.add(result.getString("id")); + } + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query key set due to: " + e.getMessage(), e); + } + + return keySet; + } + + @Override + public Set queryTypes() { + Set keySet = new HashSet<>(); + + String sql = "select distinct type from " + getTableName(); + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + try (ResultSet result = statement.executeQuery()) { + while (result.next()) { + keySet.add(result.getString("type")); + } + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + } + + return keySet; + } + + @Override + public T queryBy(String type, String id) { + + String sql = "select id, name, type, asxml from " + getTableName() + " where id = ? and type = ?"; + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + statement.setString(1, id); + statement.setString(2, type); + try (ResultSet result = statement.executeQuery()) { + if (!result.next()) { + return null; + } + + SQLXML sqlxml = result.getSQLXML("asxml"); + T t = parseFromXml(id, type, sqlxml); + if (result.next()) + throw new StrolchPersistenceException("Non unique result for query: " + sql); + return t; + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + } + } + + @Override + public List queryAll() { + + List list = new ArrayList<>(); + String sql = "select id, name, type, asxml from " + getTableName(); + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + try (ResultSet result = statement.executeQuery()) { + while (!result.next()) { + String id = result.getString("id"); + String type = result.getString("type"); + SQLXML sqlxml = result.getSQLXML("asxml"); + T t = parseFromXml(id, type, sqlxml); + list.add(t); + } + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + } + + return list; + } + + @Override + public List queryAll(String type) { + + List list = new ArrayList<>(); + String sql = "select id, name, type, asxml from " + getTableName() + " where type = ?"; + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + statement.setString(1, type); + try (ResultSet result = statement.executeQuery()) { + while (!result.next()) { + String id = result.getString("id"); + SQLXML sqlxml = result.getSQLXML("asxml"); + T t = parseFromXml(id, type, sqlxml); + list.add(t); + } + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + } + + return list; + } + + @Override + public void save(final T res) { + this.commands.add(new DaoCommand() { + @Override + public void doComand(ModificationResult modificationResult) { + internalSave(res); + modificationResult.getCreated().add(res); + } + }); + } + + @Override + public void saveAll(final List elements) { + this.commands.add(new DaoCommand() { + @Override + public void doComand(ModificationResult modificationResult) { + for (T element : elements) { + internalSave(element); + } + modificationResult.getCreated().addAll(elements); + } + }); + } + + @Override + public void update(final T element) { + this.commands.add(new DaoCommand() { + @Override + public void doComand(ModificationResult modificationResult) { + internalUpdate(element); + modificationResult.getUpdated().add(element); + } + }); + } + + @Override + public void updateAll(final List elements) { + this.commands.add(new DaoCommand() { + @Override + public void doComand(ModificationResult modificationResult) { + for (T element : elements) { + internalUpdate(element); + } + modificationResult.getUpdated().addAll(elements); + } + }); + } + + @Override + public void remove(final T element) { + this.commands.add(new DaoCommand() { + @Override + public void doComand(ModificationResult modificationResult) { + internalRemove(element); + modificationResult.getDeleted().add(element); + } + }); + } + + @Override + public void removeAll(final List elements) { + this.commands.add(new DaoCommand() { + @Override + public void doComand(ModificationResult modificationResult) { + for (T element : elements) { + internalRemove(element); + } + modificationResult.getDeleted().addAll(elements); + } + }); + } + + /** + * @param element + */ + protected abstract void internalSave(T element); + + /** + * @param element + */ + protected abstract void internalUpdate(T element); + + protected void internalRemove(final T element) { + String sql = "delete from " + getTableName() + " where id = ?"; + try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { + + preparedStatement.setString(1, element.getId()); + preparedStatement.execute(); + + } catch (SQLException e) { + throw new StrolchPersistenceException(MessageFormat.format("Failed to update Order {0} due to {2}", + element.getLocator(), e.getLocalizedMessage()), e); + } + } + + void commit(TransactionResult txResult) { + ModificationResult modificationResult = new ModificationResult(getClassName()); + txResult.addModificationResult(modificationResult); + for (DaoCommand command : this.commands) { + command.doComand(modificationResult); + } + } + + void rollback() { + this.commands.clear(); + } +} diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java index 612806108..3a2d5c7d5 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java @@ -16,8 +16,12 @@ package li.strolch.persistence.postgresql.dao.test; import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; import li.strolch.persistence.api.StrolchPersistenceHandler; +import li.strolch.persistence.postgresql.DbSchemaVersionCheck; import li.strolch.testbase.runtime.RuntimeMock; import org.junit.AfterClass; @@ -29,13 +33,18 @@ import org.junit.BeforeClass; */ public abstract class AbstractDaoImplTest extends RuntimeMock { + private static final String DB_URL = "jdbc:postgresql://localhost/testdb"; //$NON-NLS-1$ + private static final String DB_USERNAME = "testuser"; //$NON-NLS-1$ + private static final String DB_PASSWORD = "test"; //$NON-NLS-1$ private static final String RUNTIME_PATH = "target/strolchRuntime/"; //$NON-NLS-1$ private static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ private static final String CONFIG_SRC = "src/test/resources/runtime/config"; //$NON-NLS-1$ protected static StrolchPersistenceHandler persistenceHandler; @BeforeClass - public static void beforeClass() { + public static void beforeClass() throws SQLException { + + dropSchema(); File rootPath = new File(RUNTIME_PATH); File configSrc = new File(CONFIG_SRC); @@ -47,6 +56,14 @@ public abstract class AbstractDaoImplTest extends RuntimeMock { persistenceHandler = getContainer().getComponent(StrolchPersistenceHandler.class); } + private static void dropSchema() throws SQLException { + String dbVersion = DbSchemaVersionCheck.getExpectedDbVersion(); + String sql = DbSchemaVersionCheck.getSql(dbVersion, "drop"); //$NON-NLS-1$ + try (Connection connection = DriverManager.getConnection(DB_URL, DB_USERNAME, DB_PASSWORD)) { + connection.prepareStatement(sql).execute(); + } + } + @AfterClass public static void afterClass() { RuntimeMock.destroyRuntime(); diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index a5dc772aa..d47e03b26 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -28,8 +28,9 @@ import li.strolch.model.Order; import li.strolch.model.Resource; import li.strolch.model.State; import li.strolch.model.StrolchElement; +import li.strolch.model.Tags; +import li.strolch.persistence.api.ModificationResult; import li.strolch.persistence.api.StrolchTransaction; -import li.strolch.persistence.postgresql.ModificationResult; import li.strolch.runtime.observer.Observer; import li.strolch.runtime.observer.ObserverHandler; @@ -75,8 +76,8 @@ public class ObserverUpdateTest extends AbstractDaoImplTest { // register an observer for orders and resources ElementAddedObserver observer = new ElementAddedObserver(); - getContainer().getComponent(ObserverHandler.class).registerObserver("Order", observer); //$NON-NLS-1$ - getContainer().getComponent(ObserverHandler.class).registerObserver("Resource", observer); //$NON-NLS-1$ + getContainer().getComponent(ObserverHandler.class).registerObserver(Tags.ORDER, observer); + getContainer().getComponent(ObserverHandler.class).registerObserver(Tags.RESOURCE, observer); // create order Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType", new Date(), State.CREATED); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ @@ -91,8 +92,7 @@ public class ObserverUpdateTest extends AbstractDaoImplTest { } assertEquals(2, observer.results.size()); - assertEquals(1, observer.results.get("Order").getCreated().size()); //$NON-NLS-1$ - assertEquals(1, observer.results.get("Resource").getCreated().size()); //$NON-NLS-1$ - + assertEquals(1, observer.results.get(Tags.ORDER).getCreated().size()); + assertEquals(1, observer.results.get(Tags.RESOURCE).getCreated().size()); } } From 99c911258d46e8277029918294499bdebc5934ab Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 23 Dec 2013 18:43:15 +0100 Subject: [PATCH 04/61] [Major] refactored Element maps for better handling Now they are not components, now there is an ElementMapHandler which is the component and the OrderMap and ResourceMap can be retrieved from the ElementMapHandler --- .../postgresql/PostgreSqlPersistenceHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index e674844c5..1f282c61d 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -29,8 +29,8 @@ import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.StrolchPersistenceHandler; import li.strolch.persistence.api.StrolchTransaction; -import li.strolch.runtime.component.ComponentContainer; -import li.strolch.runtime.component.StrolchComponent; +import li.strolch.runtime.agent.ComponentContainerImpl; +import li.strolch.runtime.agent.StrolchComponent; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.StrolchConfigurationException; import li.strolch.runtime.observer.ObserverHandler; @@ -47,7 +47,7 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements St private ComponentConfiguration componentConfiguration; private Map connetionInfoMap; - public PostgreSqlPersistenceHandler(ComponentContainer container, String componentName) { + public PostgreSqlPersistenceHandler(ComponentContainerImpl container, String componentName) { super(container, componentName); } From bf8e41d70ef383b8018d74c9d3161eb0fa626792 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 24 Dec 2013 00:18:00 +0100 Subject: [PATCH 05/61] [New] Implemented CACHED mode for Strolch --- .../postgresql/PostgreSqlPersistenceHandler.java | 11 ++++++----- .../postgresql/dao/test/AbstractDaoImplTest.java | 6 +++--- .../resources/runtime/config/StrolchConfiguration.xml | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index 1f282c61d..bf318aba7 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -27,8 +27,9 @@ import li.strolch.persistence.api.DbConnectionInfo; import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchPersistenceException; -import li.strolch.persistence.api.StrolchPersistenceHandler; +import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.agent.ComponentContainerImpl; import li.strolch.runtime.agent.StrolchComponent; import li.strolch.runtime.configuration.ComponentConfiguration; @@ -38,7 +39,7 @@ import li.strolch.runtime.observer.ObserverHandler; /** * @author Robert von Burg */ -public class PostgreSqlPersistenceHandler extends StrolchComponent implements StrolchPersistenceHandler { +public class PostgreSqlPersistenceHandler extends StrolchComponent implements PersistenceHandler { private static final String PROP_DB_URL = "db.url"; //$NON-NLS-1$ private static final String PROP_DB_USERNAME = "db.username"; //$NON-NLS-1$ @@ -70,10 +71,10 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements St throw new StrolchConfigurationException(msg, e); } - DbConnectionInfo connectionInfo = new DbConnectionInfo(StrolchTransaction.DEFAULT_REALM, dbUrl); + DbConnectionInfo connectionInfo = new DbConnectionInfo(StrolchConstants.DEFAULT_REALM, dbUrl); connectionInfo.setUsername(username); connectionInfo.setPassword(password); - this.connetionInfoMap.put(StrolchTransaction.DEFAULT_REALM, connectionInfo); + this.connetionInfoMap.put(StrolchConstants.DEFAULT_REALM, connectionInfo); String compliant = driver.jdbcCompliant() ? "" : "non"; //$NON-NLS-1$ //$NON-NLS-2$ String msg = "Using {0} JDBC compliant Driver {1}.{2}"; //$NON-NLS-1$ @@ -98,7 +99,7 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements St } public StrolchTransaction openTx() { - return openTx(StrolchTransaction.DEFAULT_REALM); + return openTx(StrolchConstants.DEFAULT_REALM); } public StrolchTransaction openTx(String realm) { diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java index 3a2d5c7d5..5dd287cfb 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java @@ -20,7 +20,7 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; -import li.strolch.persistence.api.StrolchPersistenceHandler; +import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.postgresql.DbSchemaVersionCheck; import li.strolch.testbase.runtime.RuntimeMock; @@ -39,7 +39,7 @@ public abstract class AbstractDaoImplTest extends RuntimeMock { private static final String RUNTIME_PATH = "target/strolchRuntime/"; //$NON-NLS-1$ private static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ private static final String CONFIG_SRC = "src/test/resources/runtime/config"; //$NON-NLS-1$ - protected static StrolchPersistenceHandler persistenceHandler; + protected static PersistenceHandler persistenceHandler; @BeforeClass public static void beforeClass() throws SQLException { @@ -53,7 +53,7 @@ public abstract class AbstractDaoImplTest extends RuntimeMock { RuntimeMock.startContainer(rootPath); // initialize the component configuration - persistenceHandler = getContainer().getComponent(StrolchPersistenceHandler.class); + persistenceHandler = getContainer().getComponent(PersistenceHandler.class); } private static void dropSchema() throws SQLException { diff --git a/src/test/resources/runtime/config/StrolchConfiguration.xml b/src/test/resources/runtime/config/StrolchConfiguration.xml index 26f7d59b0..71989f732 100644 --- a/src/test/resources/runtime/config/StrolchConfiguration.xml +++ b/src/test/resources/runtime/config/StrolchConfiguration.xml @@ -3,13 +3,13 @@ StrolchPersistenceTest - EMPTY + CACHED true PersistenceHandler - li.strolch.persistence.api.StrolchPersistenceHandler + li.strolch.persistence.api.PersistenceHandler li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler true From 941b52a511398326447b0955ad7b0aa200e1f899 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 24 Dec 2013 00:36:26 +0100 Subject: [PATCH 06/61] [Major] moved OrderDao and ResourceDao factory methods to transaction It makes using transaction feel easier. --- .../PostgreSqlPersistenceHandler.java | 16 +------------- .../PostgreSqlStrolchTransaction.java | 10 +++++---- .../dao/test/ObserverUpdateTest.java | 4 ++-- .../dao/test/PostgreSqlOrderDaoTest.java | 21 ++++++++++++------- .../dao/test/PostgreSqlResourceDaoTest.java | 14 ++++++------- 5 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index bf318aba7..287aa3c2b 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -24,10 +24,8 @@ import java.util.HashMap; import java.util.Map; import li.strolch.persistence.api.DbConnectionInfo; -import li.strolch.persistence.api.OrderDao; -import li.strolch.persistence.api.ResourceDao; -import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.PersistenceHandler; +import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.agent.ComponentContainerImpl; @@ -110,18 +108,6 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe return tx; } - @Override - public OrderDao getOrderDao(StrolchTransaction tx) { - PostgreSqlStrolchTransaction sqlTx = (PostgreSqlStrolchTransaction) tx; - return sqlTx.getOrderDao(sqlTx); - } - - @Override - public ResourceDao getResourceDao(StrolchTransaction tx) { - PostgreSqlStrolchTransaction sqlTx = (PostgreSqlStrolchTransaction) tx; - return sqlTx.getResourceDao(sqlTx); - } - Connection getConnection(String realm) { DbConnectionInfo dbInfo = this.connetionInfoMap.get(realm); if (dbInfo == null) { diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index dc74d3bcb..514623fd9 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -182,15 +182,17 @@ public class PostgreSqlStrolchTransaction implements StrolchTransaction { return this.open; } - OrderDao getOrderDao(PostgreSqlStrolchTransaction tx) { + @Override + public OrderDao getOrderDao() { if (this.orderDao == null) - this.orderDao = new PostgreSqlOrderDao(tx); + this.orderDao = new PostgreSqlOrderDao(this); return (OrderDao) this.orderDao; } - ResourceDao getResourceDao(PostgreSqlStrolchTransaction tx) { + @Override + public ResourceDao getResourceDao() { if (this.resourceDao == null) - this.resourceDao = new PostgreSqlResourceDao(tx); + this.resourceDao = new PostgreSqlResourceDao(this); return (ResourceDao) this.resourceDao; } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index d47e03b26..54cfec5c5 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -82,13 +82,13 @@ public class ObserverUpdateTest extends AbstractDaoImplTest { // create order Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType", new Date(), State.CREATED); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ try (StrolchTransaction tx = persistenceHandler.openTx();) { - persistenceHandler.getOrderDao(tx).save(newOrder); + tx.getOrderDao().save(newOrder); } // create resource Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ try (StrolchTransaction tx = persistenceHandler.openTx();) { - persistenceHandler.getResourceDao(tx).save(newResource); + tx.getResourceDao().save(newResource); } assertEquals(2, observer.results.size()); diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java index 205f3bd69..ab217729b 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java @@ -34,13 +34,20 @@ public class PostgreSqlOrderDaoTest extends AbstractDaoImplTest { private static final String NAME = "Test Order"; //$NON-NLS-1$ private static final String TYPE = "ToStock"; //$NON-NLS-1$ + @Test + public void shouldStartContainer() { + try (StrolchTransaction tx = getPersistenceHandler().openTx()) { + tx.getOrderDao().queryKeySet(); + } + } + @Test public void shouldCreateOrder() { // create Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ try (StrolchTransaction tx = persistenceHandler.openTx();) { - persistenceHandler.getOrderDao(tx).save(newOrder); + tx.getOrderDao().save(newOrder); } } @@ -50,13 +57,13 @@ public class PostgreSqlOrderDaoTest extends AbstractDaoImplTest { // create Order newOrder = createOrder(ID, NAME, TYPE); try (StrolchTransaction tx = persistenceHandler.openTx();) { - persistenceHandler.getOrderDao(tx).save(newOrder); + tx.getOrderDao().save(newOrder); } // read Order readOrder = null; try (StrolchTransaction tx = persistenceHandler.openTx();) { - readOrder = persistenceHandler.getOrderDao(tx).queryBy(TYPE, ID); + readOrder = tx.getOrderDao().queryBy(TYPE, ID); } assertNotNull("Should read Order with id " + ID, readOrder); //$NON-NLS-1$ @@ -65,13 +72,13 @@ public class PostgreSqlOrderDaoTest extends AbstractDaoImplTest { String newStringValue = "Giddiya!"; //$NON-NLS-1$ sParam.setValue(newStringValue); try (StrolchTransaction tx = persistenceHandler.openTx();) { - persistenceHandler.getOrderDao(tx).update(readOrder); + tx.getOrderDao().update(readOrder); } // read updated Order updatedOrder = null; try (StrolchTransaction tx = persistenceHandler.openTx();) { - updatedOrder = persistenceHandler.getOrderDao(tx).queryBy(TYPE, ID); + updatedOrder = tx.getOrderDao().queryBy(TYPE, ID); } assertNotNull("Should read Order with id " + ID, updatedOrder); //$NON-NLS-1$ assertFalse("Objects can't be the same reference after re-reading!", readOrder == updatedOrder); //$NON-NLS-1$ @@ -80,12 +87,12 @@ public class PostgreSqlOrderDaoTest extends AbstractDaoImplTest { // delete try (StrolchTransaction tx = persistenceHandler.openTx();) { - persistenceHandler.getOrderDao(tx).remove(readOrder); + tx.getOrderDao().remove(readOrder); } // fail to re-read try (StrolchTransaction tx = persistenceHandler.openTx();) { - Order order = persistenceHandler.getOrderDao(tx).queryBy(TYPE, ID); + Order order = tx.getOrderDao().queryBy(TYPE, ID); assertNull("Should no read Order with id " + ID, order); //$NON-NLS-1$ } } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java index f1154a1e2..101cd3b9f 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java @@ -40,7 +40,7 @@ public class PostgreSqlResourceDaoTest extends AbstractDaoImplTest { // create Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ try (StrolchTransaction tx = persistenceHandler.openTx();) { - persistenceHandler.getResourceDao(tx).save(newResource); + tx.getResourceDao().save(newResource); } } @@ -50,13 +50,13 @@ public class PostgreSqlResourceDaoTest extends AbstractDaoImplTest { // create Resource newResource = createResource(ID, NAME, TYPE); try (StrolchTransaction tx = persistenceHandler.openTx();) { - persistenceHandler.getResourceDao(tx).save(newResource); + tx.getResourceDao().save(newResource); } // read Resource readResource = null; try (StrolchTransaction tx = persistenceHandler.openTx();) { - readResource = persistenceHandler.getResourceDao(tx).queryBy(TYPE, ID); + readResource = tx.getResourceDao().queryBy(TYPE, ID); } assertNotNull("Should read Resource with id " + ID, readResource); //$NON-NLS-1$ @@ -65,13 +65,13 @@ public class PostgreSqlResourceDaoTest extends AbstractDaoImplTest { String newStringValue = "Giddiya!"; //$NON-NLS-1$ sParam.setValue(newStringValue); try (StrolchTransaction tx = persistenceHandler.openTx();) { - persistenceHandler.getResourceDao(tx).update(readResource); + tx.getResourceDao().update(readResource); } // read updated Resource updatedResource = null; try (StrolchTransaction tx = persistenceHandler.openTx();) { - updatedResource = persistenceHandler.getResourceDao(tx).queryBy(TYPE, ID); + updatedResource = tx.getResourceDao().queryBy(TYPE, ID); } assertNotNull("Should read Resource with id " + ID, updatedResource); //$NON-NLS-1$ assertFalse("Objects can't be the same reference after re-reading!", readResource == updatedResource); //$NON-NLS-1$ @@ -80,12 +80,12 @@ public class PostgreSqlResourceDaoTest extends AbstractDaoImplTest { // delete try (StrolchTransaction tx = persistenceHandler.openTx();) { - persistenceHandler.getResourceDao(tx).remove(readResource); + tx.getResourceDao().remove(readResource); } // fail to re-read try (StrolchTransaction tx = persistenceHandler.openTx();) { - Resource resource = persistenceHandler.getResourceDao(tx).queryBy(TYPE, ID); + Resource resource = tx.getResourceDao().queryBy(TYPE, ID); assertNull("Should no read Resource with id " + ID, resource); //$NON-NLS-1$ } } From e27b5a96d8175ef19976518a19de42469c20f532 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 24 Dec 2013 02:12:32 +0100 Subject: [PATCH 07/61] [New] Added Unit tests to test the bulk operations --- .../PostgreSqlPersistenceHandler.java | 7 +- .../PostgreSqlStrolchTransaction.java | 36 ++++++++- .../persistence/postgresql/PostgresqlDao.java | 4 +- .../dao/test/AbstractDaoImplTest.java | 7 +- .../dao/test/PostgreSqlOrderDaoTest.java | 81 +++++++++++++++++-- .../dao/test/PostgreSqlResourceDaoTest.java | 74 +++++++++++++++++ .../dao/test/PostgresqlContainerTest.java | 60 ++++++++++++++ 7 files changed, 253 insertions(+), 16 deletions(-) create mode 100644 src/test/java/li/strolch/persistence/postgresql/dao/test/PostgresqlContainerTest.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index 287aa3c2b..950f68c8f 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -116,7 +116,12 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe } try { - return DriverManager.getConnection(dbInfo.getUrl(), dbInfo.getUsername(), dbInfo.getPassword()); + String url = dbInfo.getUrl(); + String username = dbInfo.getUsername(); + String password = dbInfo.getPassword(); + Connection connection = DriverManager.getConnection(url, username, password); + connection.setAutoCommit(false); + return connection; } catch (SQLException e) { String msg = MessageFormat.format("Failed to get a connection for {0} due to {1}", dbInfo, e.getMessage()); //$NON-NLS-1$ throw new StrolchPersistenceException(msg, e); diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index 514623fd9..bc365fdef 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -16,6 +16,7 @@ package li.strolch.persistence.postgresql; import java.sql.Connection; +import java.sql.SQLException; import java.util.Date; import java.util.Set; @@ -109,11 +110,21 @@ public class PostgreSqlStrolchTransaction implements StrolchTransaction { this.resourceDao.commit(this.txResult); } + this.connection.commit(); + this.txResult.setState(TransactionState.COMMITTED); } catch (Exception e) { - this.txResult.setState(TransactionState.FAILED); + if (this.connection != null) { + try { + this.connection.rollback(); + } catch (SQLException e1) { + logger.error("Failed to rollback transation due to " + e.getMessage(), e); //$NON-NLS-1$ + } + } + + this.txResult.setState(TransactionState.FAILED); long end = System.nanoTime(); long txDuration = end - this.startTime; long closeDuration = end - start; @@ -124,7 +135,14 @@ public class PostgreSqlStrolchTransaction implements StrolchTransaction { sb.append(StringHelper.formatNanoDuration(closeDuration)); logger.info(sb.toString()); - throw e; + throw new StrolchPersistenceException("Strolch Transaction failed due to " + e.getMessage(), e); //$NON-NLS-1$ + + } finally { + try { + this.connection.close(); + } catch (Exception e) { + logger.error("Failed to close connection due to " + e.getMessage(), e); //$NON-NLS-1$ + } } long end = System.nanoTime(); @@ -160,6 +178,20 @@ public class PostgreSqlStrolchTransaction implements StrolchTransaction { public void autoCloseableRollback() { long start = System.nanoTime(); + if (this.connection != null) { + try { + this.connection.rollback(); + } catch (SQLException e) { + throw new StrolchPersistenceException("Strolch Transaction failed due to " + e.getMessage(), e); //$NON-NLS-1$ + } finally { + try { + this.connection.close(); + } catch (Exception e) { + logger.error("Failed to close connection due to " + e.getMessage(), e); //$NON-NLS-1$ + } + } + } + long end = System.nanoTime(); long txDuration = end - this.startTime; long closeDuration = end - start; diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java index 68a803523..67bd4496c 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java @@ -137,7 +137,7 @@ public abstract class PostgresqlDao implements Strolch String sql = "select id, name, type, asxml from " + getTableName(); try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { try (ResultSet result = statement.executeQuery()) { - while (!result.next()) { + while (result.next()) { String id = result.getString("id"); String type = result.getString("type"); SQLXML sqlxml = result.getSQLXML("asxml"); @@ -160,7 +160,7 @@ public abstract class PostgresqlDao implements Strolch try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); try (ResultSet result = statement.executeQuery()) { - while (!result.next()) { + while (result.next()) { String id = result.getString("id"); SQLXML sqlxml = result.getSQLXML("asxml"); T t = parseFromXml(id, type, sqlxml); diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java index 5dd287cfb..f386ff809 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java @@ -29,16 +29,15 @@ import org.junit.BeforeClass; /** * @author Robert von Burg - * */ public abstract class AbstractDaoImplTest extends RuntimeMock { private static final String DB_URL = "jdbc:postgresql://localhost/testdb"; //$NON-NLS-1$ private static final String DB_USERNAME = "testuser"; //$NON-NLS-1$ private static final String DB_PASSWORD = "test"; //$NON-NLS-1$ - private static final String RUNTIME_PATH = "target/strolchRuntime/"; //$NON-NLS-1$ - private static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ - private static final String CONFIG_SRC = "src/test/resources/runtime/config"; //$NON-NLS-1$ + public static final String RUNTIME_PATH = "target/strolchRuntime/"; //$NON-NLS-1$ + public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ + public static final String CONFIG_SRC = "src/test/resources/runtime/config"; //$NON-NLS-1$ protected static PersistenceHandler persistenceHandler; @BeforeClass diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java index ab217729b..b8af91c09 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java @@ -18,12 +18,22 @@ package li.strolch.persistence.postgresql.dao.test; import static li.strolch.model.ModelGenerator.BAG_ID; import static li.strolch.model.ModelGenerator.PARAM_STRING_ID; import static li.strolch.model.ModelGenerator.createOrder; +import static li.strolch.model.ModelGenerator.createOrders; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import li.strolch.model.Order; import li.strolch.model.parameter.Parameter; +import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.StrolchTransaction; import org.junit.Test; @@ -34,13 +44,6 @@ public class PostgreSqlOrderDaoTest extends AbstractDaoImplTest { private static final String NAME = "Test Order"; //$NON-NLS-1$ private static final String TYPE = "ToStock"; //$NON-NLS-1$ - @Test - public void shouldStartContainer() { - try (StrolchTransaction tx = getPersistenceHandler().openTx()) { - tx.getOrderDao().queryKeySet(); - } - } - @Test public void shouldCreateOrder() { @@ -96,4 +99,68 @@ public class PostgreSqlOrderDaoTest extends AbstractDaoImplTest { assertNull("Should no read Order with id " + ID, order); //$NON-NLS-1$ } } + + @SuppressWarnings("nls") + @Test + public void shouldPerformBulkOperations() { + + List orders = new ArrayList<>(); + orders.addAll(createOrders(orders.size(), 5, "@", "My Order ", "MyType1")); + orders.addAll(createOrders(orders.size(), 5, "@", "Other Order ", "MyType2")); + orders.addAll(createOrders(orders.size(), 5, "@", "Further Order ", "MyType3")); + + Comparator comparator = new Comparator() { + @Override + public int compare(Order o1, Order o2) { + return o1.getId().compareTo(o2.getId()); + } + }; + Collections.sort(orders, comparator); + + try (StrolchTransaction tx = persistenceHandler.openTx()) { + tx.getOrderDao().removeAll(tx.getOrderDao().queryAll()); + } + + try (StrolchTransaction tx = persistenceHandler.openTx()) { + tx.getOrderDao().saveAll(orders); + } + + Set expectedTypes = new HashSet<>(); + expectedTypes.add("MyType1"); + expectedTypes.add("MyType2"); + expectedTypes.add("MyType3"); + + try (StrolchTransaction tx = persistenceHandler.openTx()) { + List allOrders = tx.getOrderDao().queryAll(); + Collections.sort(allOrders, comparator); + assertEquals(orders, allOrders); + } + + try (StrolchTransaction tx = persistenceHandler.openTx()) { + OrderDao orderDao = tx.getOrderDao(); + + Set types = orderDao.queryTypes(); + assertEquals(expectedTypes, types); + + Set keySet = orderDao.queryKeySet(); + assertEquals(15, keySet.size()); + + for (String type : types) { + Set idsByType = orderDao.queryKeySet(type); + assertEquals(5, idsByType.size()); + + List ordersByType = orderDao.queryAll(type); + assertEquals(5, ordersByType.size()); + } + } + + try (StrolchTransaction tx = persistenceHandler.openTx()) { + Order order = tx.getOrderDao().queryBy("MyType1", "@_1"); + assertNotNull(order); + order = tx.getOrderDao().queryBy("MyType2", "@_6"); + assertNotNull(order); + order = tx.getOrderDao().queryBy("MyType3", "@_11"); + assertNotNull(order); + } + } } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java index 101cd3b9f..de2db7ed7 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java @@ -18,12 +18,22 @@ package li.strolch.persistence.postgresql.dao.test; import static li.strolch.model.ModelGenerator.BAG_ID; import static li.strolch.model.ModelGenerator.PARAM_STRING_ID; import static li.strolch.model.ModelGenerator.createResource; +import static li.strolch.model.ModelGenerator.createResources; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import li.strolch.model.Resource; import li.strolch.model.parameter.Parameter; +import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchTransaction; import org.junit.Test; @@ -89,4 +99,68 @@ public class PostgreSqlResourceDaoTest extends AbstractDaoImplTest { assertNull("Should no read Resource with id " + ID, resource); //$NON-NLS-1$ } } + + @SuppressWarnings("nls") + @Test + public void shouldPerformBulkOperations() { + + List resources = new ArrayList<>(); + resources.addAll(createResources(resources.size(), 5, "@", "My Resource ", "MyType1")); + resources.addAll(createResources(resources.size(), 5, "@", "Other Resource ", "MyType2")); + resources.addAll(createResources(resources.size(), 5, "@", "Further Resource ", "MyType3")); + + Comparator comparator = new Comparator() { + @Override + public int compare(Resource o1, Resource o2) { + return o1.getId().compareTo(o2.getId()); + } + }; + Collections.sort(resources, comparator); + + try (StrolchTransaction tx = persistenceHandler.openTx()) { + tx.getResourceDao().removeAll(tx.getResourceDao().queryAll()); + } + + try (StrolchTransaction tx = persistenceHandler.openTx()) { + tx.getResourceDao().saveAll(resources); + } + + Set expectedTypes = new HashSet<>(); + expectedTypes.add("MyType1"); + expectedTypes.add("MyType2"); + expectedTypes.add("MyType3"); + + try (StrolchTransaction tx = persistenceHandler.openTx()) { + List allResources = tx.getResourceDao().queryAll(); + Collections.sort(allResources, comparator); + assertEquals(resources, allResources); + } + + try (StrolchTransaction tx = persistenceHandler.openTx()) { + ResourceDao resourceDao = tx.getResourceDao(); + + Set types = resourceDao.queryTypes(); + assertEquals(expectedTypes, types); + + Set keySet = resourceDao.queryKeySet(); + assertEquals(15, keySet.size()); + + for (String type : types) { + Set idsByType = resourceDao.queryKeySet(type); + assertEquals(5, idsByType.size()); + + List resourcesByType = resourceDao.queryAll(type); + assertEquals(5, resourcesByType.size()); + } + } + + try (StrolchTransaction tx = persistenceHandler.openTx()) { + Resource resource = tx.getResourceDao().queryBy("MyType1", "@_1"); + assertNotNull(resource); + resource = tx.getResourceDao().queryBy("MyType2", "@_6"); + assertNotNull(resource); + resource = tx.getResourceDao().queryBy("MyType3", "@_11"); + assertNotNull(resource); + } + } } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgresqlContainerTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgresqlContainerTest.java new file mode 100644 index 000000000..2bf09f700 --- /dev/null +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgresqlContainerTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql.dao.test; + +import java.io.File; +import java.sql.SQLException; + +import li.strolch.persistence.api.PersistenceHandler; +import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.testbase.runtime.RuntimeMock; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * @author Robert von Burg + */ +public class PostgresqlContainerTest extends RuntimeMock { + + protected static PersistenceHandler persistenceHandler; + + @BeforeClass + public static void beforeClass() throws SQLException { + + File rootPath = new File(AbstractDaoImplTest.RUNTIME_PATH); + File configSrc = new File(AbstractDaoImplTest.CONFIG_SRC); + RuntimeMock.mockRuntime(rootPath, configSrc); + new File(rootPath, AbstractDaoImplTest.DB_STORE_PATH_DIR).mkdir(); + RuntimeMock.startContainer(rootPath); + + // initialize the component configuration + persistenceHandler = getContainer().getComponent(PersistenceHandler.class); + } + + @Test + public void shouldStartContainer() { + try (StrolchTransaction tx = getPersistenceHandler().openTx()) { + tx.getOrderDao().queryKeySet(); + } + } + + @AfterClass + public static void afterClass() { + RuntimeMock.destroyRuntime(); + } +} From 5f0419d13fd9fd756edaaa50d3ec4030d45596ed Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 24 Dec 2013 02:43:47 +0100 Subject: [PATCH 08/61] [Minor] set artifact name to artifactId for easier reading of build log --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 70d4636c2..644f000ef 100644 --- a/pom.xml +++ b/pom.xml @@ -12,8 +12,8 @@ li.strolch.persistence.postgresql - Reference Persistence Implementation for Strolch - Reference Persistence Implementation for Strolch + li.strolch.persistence.postgresql + PostgreSQL Persistence Implementation for Strolch https://github.com/eitch/li.strolch.persistence.postgresql From e9d470676e7330eb0116a540951c1a2a7a147d1b Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 24 Dec 2013 02:47:11 +0100 Subject: [PATCH 09/61] [New] methods to generate bulk objects now pad the id This allows for easier lexical sorting --- .../postgresql/dao/test/PostgreSqlOrderDaoTest.java | 6 +++--- .../postgresql/dao/test/PostgreSqlResourceDaoTest.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java index b8af91c09..1e7bef900 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java @@ -155,11 +155,11 @@ public class PostgreSqlOrderDaoTest extends AbstractDaoImplTest { } try (StrolchTransaction tx = persistenceHandler.openTx()) { - Order order = tx.getOrderDao().queryBy("MyType1", "@_1"); + Order order = tx.getOrderDao().queryBy("MyType1", "@_00000001"); assertNotNull(order); - order = tx.getOrderDao().queryBy("MyType2", "@_6"); + order = tx.getOrderDao().queryBy("MyType2", "@_00000006"); assertNotNull(order); - order = tx.getOrderDao().queryBy("MyType3", "@_11"); + order = tx.getOrderDao().queryBy("MyType3", "@_00000011"); assertNotNull(order); } } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java index de2db7ed7..40f61af94 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java @@ -155,11 +155,11 @@ public class PostgreSqlResourceDaoTest extends AbstractDaoImplTest { } try (StrolchTransaction tx = persistenceHandler.openTx()) { - Resource resource = tx.getResourceDao().queryBy("MyType1", "@_1"); + Resource resource = tx.getResourceDao().queryBy("MyType1", "@_00000001"); assertNotNull(resource); - resource = tx.getResourceDao().queryBy("MyType2", "@_6"); + resource = tx.getResourceDao().queryBy("MyType2", "@_00000006"); assertNotNull(resource); - resource = tx.getResourceDao().queryBy("MyType3", "@_11"); + resource = tx.getResourceDao().queryBy("MyType3", "@_00000011"); assertNotNull(resource); } } From 08c2baf4e8276ad40c96bf125633afe2bde65b5e Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 25 Dec 2013 11:56:11 +0100 Subject: [PATCH 10/61] [Minor] fixed issue where eclipse couldn't validate log4j.xml --- src/test/resources/log4j.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/resources/log4j.xml b/src/test/resources/log4j.xml index a35a3c351..0a2a73d06 100644 --- a/src/test/resources/log4j.xml +++ b/src/test/resources/log4j.xml @@ -1,5 +1,6 @@ - + From 295a5e0063623b746cfb74d64f127ed69775a227 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 25 Dec 2013 17:02:27 +0100 Subject: [PATCH 11/61] [Minor] refactored tests for persistence layers to remove duplicate code --- .../dao/test/AbstractDaoImplTest.java | 23 ++- .../dao/test/ObserverUpdateTest.java | 8 +- .../dao/test/PostgreSqlOrderDaoTest.java | 136 +---------------- .../dao/test/PostgreSqlResourceDaoTest.java | 138 +----------------- .../dao/test/PostgresqlContainerTest.java | 17 +-- 5 files changed, 37 insertions(+), 285 deletions(-) diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java index f386ff809..897c65d64 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java @@ -20,7 +20,6 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; -import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.postgresql.DbSchemaVersionCheck; import li.strolch.testbase.runtime.RuntimeMock; @@ -30,15 +29,17 @@ import org.junit.BeforeClass; /** * @author Robert von Burg */ -public abstract class AbstractDaoImplTest extends RuntimeMock { +public abstract class AbstractDaoImplTest { + + public static final String RUNTIME_PATH = "target/strolchRuntime/"; //$NON-NLS-1$ + public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ + public static final String CONFIG_SRC = "src/test/resources/runtime/config"; //$NON-NLS-1$ private static final String DB_URL = "jdbc:postgresql://localhost/testdb"; //$NON-NLS-1$ private static final String DB_USERNAME = "testuser"; //$NON-NLS-1$ private static final String DB_PASSWORD = "test"; //$NON-NLS-1$ - public static final String RUNTIME_PATH = "target/strolchRuntime/"; //$NON-NLS-1$ - public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ - public static final String CONFIG_SRC = "src/test/resources/runtime/config"; //$NON-NLS-1$ - protected static PersistenceHandler persistenceHandler; + + protected static RuntimeMock runtimeMock; @BeforeClass public static void beforeClass() throws SQLException { @@ -47,12 +48,10 @@ public abstract class AbstractDaoImplTest extends RuntimeMock { File rootPath = new File(RUNTIME_PATH); File configSrc = new File(CONFIG_SRC); - RuntimeMock.mockRuntime(rootPath, configSrc); + runtimeMock = new RuntimeMock(); + runtimeMock.mockRuntime(rootPath, configSrc); new File(rootPath, DB_STORE_PATH_DIR).mkdir(); - RuntimeMock.startContainer(rootPath); - - // initialize the component configuration - persistenceHandler = getContainer().getComponent(PersistenceHandler.class); + runtimeMock.startContainer(rootPath); } private static void dropSchema() throws SQLException { @@ -65,6 +64,6 @@ public abstract class AbstractDaoImplTest extends RuntimeMock { @AfterClass public static void afterClass() { - RuntimeMock.destroyRuntime(); + runtimeMock.destroyRuntime(); } } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index 54cfec5c5..9c145f6ec 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -76,18 +76,18 @@ public class ObserverUpdateTest extends AbstractDaoImplTest { // register an observer for orders and resources ElementAddedObserver observer = new ElementAddedObserver(); - getContainer().getComponent(ObserverHandler.class).registerObserver(Tags.ORDER, observer); - getContainer().getComponent(ObserverHandler.class).registerObserver(Tags.RESOURCE, observer); + runtimeMock.getContainer().getComponent(ObserverHandler.class).registerObserver(Tags.ORDER, observer); + runtimeMock.getContainer().getComponent(ObserverHandler.class).registerObserver(Tags.RESOURCE, observer); // create order Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType", new Date(), State.CREATED); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = persistenceHandler.openTx();) { + try (StrolchTransaction tx = runtimeMock.getPersistenceHandler().openTx();) { tx.getOrderDao().save(newOrder); } // create resource Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = persistenceHandler.openTx();) { + try (StrolchTransaction tx = runtimeMock.getPersistenceHandler().openTx();) { tx.getResourceDao().save(newResource); } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java index 1e7bef900..89bda1f39 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java @@ -15,152 +15,30 @@ */ package li.strolch.persistence.postgresql.dao.test; -import static li.strolch.model.ModelGenerator.BAG_ID; -import static li.strolch.model.ModelGenerator.PARAM_STRING_ID; -import static li.strolch.model.ModelGenerator.createOrder; -import static li.strolch.model.ModelGenerator.createOrders; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import li.strolch.model.Order; -import li.strolch.model.parameter.Parameter; -import li.strolch.persistence.api.OrderDao; -import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.testbase.runtime.OrderModelTestRunner; import org.junit.Test; public class PostgreSqlOrderDaoTest extends AbstractDaoImplTest { - private static final String ID = "@testOrder"; //$NON-NLS-1$ - private static final String NAME = "Test Order"; //$NON-NLS-1$ - private static final String TYPE = "ToStock"; //$NON-NLS-1$ - @Test public void shouldCreateOrder() { - // create - Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = persistenceHandler.openTx();) { - tx.getOrderDao().save(newOrder); - } + OrderModelTestRunner testRunner = new OrderModelTestRunner(runtimeMock); + testRunner.runCreateOrderTest(); } @Test public void shouldCrud() { - // create - Order newOrder = createOrder(ID, NAME, TYPE); - try (StrolchTransaction tx = persistenceHandler.openTx();) { - tx.getOrderDao().save(newOrder); - } - - // read - Order readOrder = null; - try (StrolchTransaction tx = persistenceHandler.openTx();) { - readOrder = tx.getOrderDao().queryBy(TYPE, ID); - } - assertNotNull("Should read Order with id " + ID, readOrder); //$NON-NLS-1$ - - // update - Parameter sParam = readOrder.getParameter(BAG_ID, PARAM_STRING_ID); - String newStringValue = "Giddiya!"; //$NON-NLS-1$ - sParam.setValue(newStringValue); - try (StrolchTransaction tx = persistenceHandler.openTx();) { - tx.getOrderDao().update(readOrder); - } - - // read updated - Order updatedOrder = null; - try (StrolchTransaction tx = persistenceHandler.openTx();) { - updatedOrder = tx.getOrderDao().queryBy(TYPE, ID); - } - assertNotNull("Should read Order with id " + ID, updatedOrder); //$NON-NLS-1$ - assertFalse("Objects can't be the same reference after re-reading!", readOrder == updatedOrder); //$NON-NLS-1$ - Parameter updatedParam = readOrder.getParameter(BAG_ID, PARAM_STRING_ID); - assertEquals(newStringValue, updatedParam.getValue()); - - // delete - try (StrolchTransaction tx = persistenceHandler.openTx();) { - tx.getOrderDao().remove(readOrder); - } - - // fail to re-read - try (StrolchTransaction tx = persistenceHandler.openTx();) { - Order order = tx.getOrderDao().queryBy(TYPE, ID); - assertNull("Should no read Order with id " + ID, order); //$NON-NLS-1$ - } + OrderModelTestRunner testRunner = new OrderModelTestRunner(runtimeMock); + testRunner.runCrudTests(); } - @SuppressWarnings("nls") @Test public void shouldPerformBulkOperations() { - List orders = new ArrayList<>(); - orders.addAll(createOrders(orders.size(), 5, "@", "My Order ", "MyType1")); - orders.addAll(createOrders(orders.size(), 5, "@", "Other Order ", "MyType2")); - orders.addAll(createOrders(orders.size(), 5, "@", "Further Order ", "MyType3")); - - Comparator comparator = new Comparator() { - @Override - public int compare(Order o1, Order o2) { - return o1.getId().compareTo(o2.getId()); - } - }; - Collections.sort(orders, comparator); - - try (StrolchTransaction tx = persistenceHandler.openTx()) { - tx.getOrderDao().removeAll(tx.getOrderDao().queryAll()); - } - - try (StrolchTransaction tx = persistenceHandler.openTx()) { - tx.getOrderDao().saveAll(orders); - } - - Set expectedTypes = new HashSet<>(); - expectedTypes.add("MyType1"); - expectedTypes.add("MyType2"); - expectedTypes.add("MyType3"); - - try (StrolchTransaction tx = persistenceHandler.openTx()) { - List allOrders = tx.getOrderDao().queryAll(); - Collections.sort(allOrders, comparator); - assertEquals(orders, allOrders); - } - - try (StrolchTransaction tx = persistenceHandler.openTx()) { - OrderDao orderDao = tx.getOrderDao(); - - Set types = orderDao.queryTypes(); - assertEquals(expectedTypes, types); - - Set keySet = orderDao.queryKeySet(); - assertEquals(15, keySet.size()); - - for (String type : types) { - Set idsByType = orderDao.queryKeySet(type); - assertEquals(5, idsByType.size()); - - List ordersByType = orderDao.queryAll(type); - assertEquals(5, ordersByType.size()); - } - } - - try (StrolchTransaction tx = persistenceHandler.openTx()) { - Order order = tx.getOrderDao().queryBy("MyType1", "@_00000001"); - assertNotNull(order); - order = tx.getOrderDao().queryBy("MyType2", "@_00000006"); - assertNotNull(order); - order = tx.getOrderDao().queryBy("MyType3", "@_00000011"); - assertNotNull(order); - } + OrderModelTestRunner testRunner = new OrderModelTestRunner(runtimeMock); + testRunner.runBulkOperationTests(); } } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java index 40f61af94..695220574 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java @@ -15,152 +15,30 @@ */ package li.strolch.persistence.postgresql.dao.test; -import static li.strolch.model.ModelGenerator.BAG_ID; -import static li.strolch.model.ModelGenerator.PARAM_STRING_ID; -import static li.strolch.model.ModelGenerator.createResource; -import static li.strolch.model.ModelGenerator.createResources; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import li.strolch.model.Resource; -import li.strolch.model.parameter.Parameter; -import li.strolch.persistence.api.ResourceDao; -import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.testbase.runtime.ResourceModelTestRunner; import org.junit.Test; public class PostgreSqlResourceDaoTest extends AbstractDaoImplTest { - private static final String ID = "@testResource"; //$NON-NLS-1$ - private static final String NAME = "Test Resource"; //$NON-NLS-1$ - private static final String TYPE = "Box"; //$NON-NLS-1$ - @Test - public void shouldCreateResource() { + public void shouldCreateOrder() { - // create - Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = persistenceHandler.openTx();) { - tx.getResourceDao().save(newResource); - } + ResourceModelTestRunner testRunner = new ResourceModelTestRunner(runtimeMock); + testRunner.runCreateResourceTest(); } @Test public void shouldCrud() { - // create - Resource newResource = createResource(ID, NAME, TYPE); - try (StrolchTransaction tx = persistenceHandler.openTx();) { - tx.getResourceDao().save(newResource); - } - - // read - Resource readResource = null; - try (StrolchTransaction tx = persistenceHandler.openTx();) { - readResource = tx.getResourceDao().queryBy(TYPE, ID); - } - assertNotNull("Should read Resource with id " + ID, readResource); //$NON-NLS-1$ - - // update - Parameter sParam = readResource.getParameter(BAG_ID, PARAM_STRING_ID); - String newStringValue = "Giddiya!"; //$NON-NLS-1$ - sParam.setValue(newStringValue); - try (StrolchTransaction tx = persistenceHandler.openTx();) { - tx.getResourceDao().update(readResource); - } - - // read updated - Resource updatedResource = null; - try (StrolchTransaction tx = persistenceHandler.openTx();) { - updatedResource = tx.getResourceDao().queryBy(TYPE, ID); - } - assertNotNull("Should read Resource with id " + ID, updatedResource); //$NON-NLS-1$ - assertFalse("Objects can't be the same reference after re-reading!", readResource == updatedResource); //$NON-NLS-1$ - Parameter updatedParam = readResource.getParameter(BAG_ID, PARAM_STRING_ID); - assertEquals(newStringValue, updatedParam.getValue()); - - // delete - try (StrolchTransaction tx = persistenceHandler.openTx();) { - tx.getResourceDao().remove(readResource); - } - - // fail to re-read - try (StrolchTransaction tx = persistenceHandler.openTx();) { - Resource resource = tx.getResourceDao().queryBy(TYPE, ID); - assertNull("Should no read Resource with id " + ID, resource); //$NON-NLS-1$ - } + ResourceModelTestRunner testRunner = new ResourceModelTestRunner(runtimeMock); + testRunner.runCrudTests(); } - @SuppressWarnings("nls") @Test public void shouldPerformBulkOperations() { - List resources = new ArrayList<>(); - resources.addAll(createResources(resources.size(), 5, "@", "My Resource ", "MyType1")); - resources.addAll(createResources(resources.size(), 5, "@", "Other Resource ", "MyType2")); - resources.addAll(createResources(resources.size(), 5, "@", "Further Resource ", "MyType3")); - - Comparator comparator = new Comparator() { - @Override - public int compare(Resource o1, Resource o2) { - return o1.getId().compareTo(o2.getId()); - } - }; - Collections.sort(resources, comparator); - - try (StrolchTransaction tx = persistenceHandler.openTx()) { - tx.getResourceDao().removeAll(tx.getResourceDao().queryAll()); - } - - try (StrolchTransaction tx = persistenceHandler.openTx()) { - tx.getResourceDao().saveAll(resources); - } - - Set expectedTypes = new HashSet<>(); - expectedTypes.add("MyType1"); - expectedTypes.add("MyType2"); - expectedTypes.add("MyType3"); - - try (StrolchTransaction tx = persistenceHandler.openTx()) { - List allResources = tx.getResourceDao().queryAll(); - Collections.sort(allResources, comparator); - assertEquals(resources, allResources); - } - - try (StrolchTransaction tx = persistenceHandler.openTx()) { - ResourceDao resourceDao = tx.getResourceDao(); - - Set types = resourceDao.queryTypes(); - assertEquals(expectedTypes, types); - - Set keySet = resourceDao.queryKeySet(); - assertEquals(15, keySet.size()); - - for (String type : types) { - Set idsByType = resourceDao.queryKeySet(type); - assertEquals(5, idsByType.size()); - - List resourcesByType = resourceDao.queryAll(type); - assertEquals(5, resourcesByType.size()); - } - } - - try (StrolchTransaction tx = persistenceHandler.openTx()) { - Resource resource = tx.getResourceDao().queryBy("MyType1", "@_00000001"); - assertNotNull(resource); - resource = tx.getResourceDao().queryBy("MyType2", "@_00000006"); - assertNotNull(resource); - resource = tx.getResourceDao().queryBy("MyType3", "@_00000011"); - assertNotNull(resource); - } + ResourceModelTestRunner testRunner = new ResourceModelTestRunner(runtimeMock); + testRunner.runBulkOperationTests(); } } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgresqlContainerTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgresqlContainerTest.java index 2bf09f700..6b5b99d58 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgresqlContainerTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgresqlContainerTest.java @@ -18,7 +18,6 @@ package li.strolch.persistence.postgresql.dao.test; import java.io.File; import java.sql.SQLException; -import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.testbase.runtime.RuntimeMock; @@ -29,32 +28,30 @@ import org.junit.Test; /** * @author Robert von Burg */ -public class PostgresqlContainerTest extends RuntimeMock { +public class PostgresqlContainerTest { - protected static PersistenceHandler persistenceHandler; + private static RuntimeMock runtimeMock; @BeforeClass public static void beforeClass() throws SQLException { File rootPath = new File(AbstractDaoImplTest.RUNTIME_PATH); File configSrc = new File(AbstractDaoImplTest.CONFIG_SRC); - RuntimeMock.mockRuntime(rootPath, configSrc); + runtimeMock = new RuntimeMock(); + runtimeMock.mockRuntime(rootPath, configSrc); new File(rootPath, AbstractDaoImplTest.DB_STORE_PATH_DIR).mkdir(); - RuntimeMock.startContainer(rootPath); - - // initialize the component configuration - persistenceHandler = getContainer().getComponent(PersistenceHandler.class); + runtimeMock.startContainer(rootPath); } @Test public void shouldStartContainer() { - try (StrolchTransaction tx = getPersistenceHandler().openTx()) { + try (StrolchTransaction tx = runtimeMock.getPersistenceHandler().openTx()) { tx.getOrderDao().queryKeySet(); } } @AfterClass public static void afterClass() { - RuntimeMock.destroyRuntime(); + runtimeMock.destroyRuntime(); } } From 36c02bad0cc4e2af96e3bb9701123d24224bce15 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 25 Dec 2013 17:34:03 +0100 Subject: [PATCH 12/61] [Minor] refactored tests for persistence layers to remove duplicate code --- .../dao/test/ObserverUpdateTest.java | 33 ++++++++++- .../dao/test/PostgreSqlOrderDaoTest.java | 44 -------------- .../dao/test/PostgreSqlResourceDaoTest.java | 44 -------------- .../dao/test/PostgresqlContainerTest.java | 57 ------------------- ...DaoImplTest.java => XmlCachedDaoTest.java} | 11 ++-- 5 files changed, 38 insertions(+), 151 deletions(-) delete mode 100644 src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java delete mode 100644 src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java delete mode 100644 src/test/java/li/strolch/persistence/postgresql/dao/test/PostgresqlContainerTest.java rename src/test/java/li/strolch/persistence/postgresql/dao/test/{AbstractDaoImplTest.java => XmlCachedDaoTest.java} (92%) diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index 9c145f6ec..b2542bf34 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -19,6 +19,7 @@ import static li.strolch.model.ModelGenerator.createOrder; import static li.strolch.model.ModelGenerator.createResource; import static org.junit.Assert.assertEquals; +import java.io.File; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -33,14 +34,42 @@ import li.strolch.persistence.api.ModificationResult; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.runtime.observer.Observer; import li.strolch.runtime.observer.ObserverHandler; +import li.strolch.testbase.runtime.RuntimeMock; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; /** * @author Robert von Burg - * */ -public class ObserverUpdateTest extends AbstractDaoImplTest { +public class ObserverUpdateTest { + + public static final String RUNTIME_PATH = "target/strolchRuntime/"; //$NON-NLS-1$ + public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ + public static final String CONFIG_SRC = "src/test/resources/runtime/config"; //$NON-NLS-1$ + + protected static RuntimeMock runtimeMock; + + protected RuntimeMock getRuntimeMock() { + return runtimeMock; + } + + @BeforeClass + public static void beforeClass() { + + File rootPath = new File(RUNTIME_PATH); + File configSrc = new File(CONFIG_SRC); + runtimeMock = new RuntimeMock(); + runtimeMock.mockRuntime(rootPath, configSrc); + new File(rootPath, DB_STORE_PATH_DIR).mkdir(); + runtimeMock.startContainer(rootPath); + } + + @AfterClass + public static void afterClass() { + runtimeMock.destroyRuntime(); + } public final class ElementAddedObserver implements Observer { diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java deleted file mode 100644 index 89bda1f39..000000000 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlOrderDaoTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013 Robert von Burg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package li.strolch.persistence.postgresql.dao.test; - -import li.strolch.testbase.runtime.OrderModelTestRunner; - -import org.junit.Test; - -public class PostgreSqlOrderDaoTest extends AbstractDaoImplTest { - - @Test - public void shouldCreateOrder() { - - OrderModelTestRunner testRunner = new OrderModelTestRunner(runtimeMock); - testRunner.runCreateOrderTest(); - } - - @Test - public void shouldCrud() { - - OrderModelTestRunner testRunner = new OrderModelTestRunner(runtimeMock); - testRunner.runCrudTests(); - } - - @Test - public void shouldPerformBulkOperations() { - - OrderModelTestRunner testRunner = new OrderModelTestRunner(runtimeMock); - testRunner.runBulkOperationTests(); - } -} diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java deleted file mode 100644 index 695220574..000000000 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgreSqlResourceDaoTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013 Robert von Burg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package li.strolch.persistence.postgresql.dao.test; - -import li.strolch.testbase.runtime.ResourceModelTestRunner; - -import org.junit.Test; - -public class PostgreSqlResourceDaoTest extends AbstractDaoImplTest { - - @Test - public void shouldCreateOrder() { - - ResourceModelTestRunner testRunner = new ResourceModelTestRunner(runtimeMock); - testRunner.runCreateResourceTest(); - } - - @Test - public void shouldCrud() { - - ResourceModelTestRunner testRunner = new ResourceModelTestRunner(runtimeMock); - testRunner.runCrudTests(); - } - - @Test - public void shouldPerformBulkOperations() { - - ResourceModelTestRunner testRunner = new ResourceModelTestRunner(runtimeMock); - testRunner.runBulkOperationTests(); - } -} diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgresqlContainerTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgresqlContainerTest.java deleted file mode 100644 index 6b5b99d58..000000000 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/PostgresqlContainerTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2013 Robert von Burg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package li.strolch.persistence.postgresql.dao.test; - -import java.io.File; -import java.sql.SQLException; - -import li.strolch.persistence.api.StrolchTransaction; -import li.strolch.testbase.runtime.RuntimeMock; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - -/** - * @author Robert von Burg - */ -public class PostgresqlContainerTest { - - private static RuntimeMock runtimeMock; - - @BeforeClass - public static void beforeClass() throws SQLException { - - File rootPath = new File(AbstractDaoImplTest.RUNTIME_PATH); - File configSrc = new File(AbstractDaoImplTest.CONFIG_SRC); - runtimeMock = new RuntimeMock(); - runtimeMock.mockRuntime(rootPath, configSrc); - new File(rootPath, AbstractDaoImplTest.DB_STORE_PATH_DIR).mkdir(); - runtimeMock.startContainer(rootPath); - } - - @Test - public void shouldStartContainer() { - try (StrolchTransaction tx = runtimeMock.getPersistenceHandler().openTx()) { - tx.getOrderDao().queryKeySet(); - } - } - - @AfterClass - public static void afterClass() { - runtimeMock.destroyRuntime(); - } -} diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java similarity index 92% rename from src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java rename to src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java index 897c65d64..70389ca86 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/AbstractDaoImplTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java @@ -21,15 +21,13 @@ import java.sql.DriverManager; import java.sql.SQLException; import li.strolch.persistence.postgresql.DbSchemaVersionCheck; +import li.strolch.testbase.runtime.AbstractModelTest; import li.strolch.testbase.runtime.RuntimeMock; import org.junit.AfterClass; import org.junit.BeforeClass; -/** - * @author Robert von Burg - */ -public abstract class AbstractDaoImplTest { +public class XmlCachedDaoTest extends AbstractModelTest { public static final String RUNTIME_PATH = "target/strolchRuntime/"; //$NON-NLS-1$ public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ @@ -40,6 +38,11 @@ public abstract class AbstractDaoImplTest { private static final String DB_PASSWORD = "test"; //$NON-NLS-1$ protected static RuntimeMock runtimeMock; + + @Override + protected RuntimeMock getRuntimeMock() { + return runtimeMock; + } @BeforeClass public static void beforeClass() throws SQLException { From fe3cca7cb3486fbccce40f054a40da4193343e3c Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 25 Dec 2013 17:40:30 +0100 Subject: [PATCH 13/61] [Minor] schema must be dropped in all tests... --- .../persistence/postgresql/dao/test/ObserverUpdateTest.java | 5 ++++- .../persistence/postgresql/dao/test/XmlCachedDaoTest.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index b2542bf34..ce20eaee6 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -20,6 +20,7 @@ import static li.strolch.model.ModelGenerator.createResource; import static org.junit.Assert.assertEquals; import java.io.File; +import java.sql.SQLException; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -56,7 +57,9 @@ public class ObserverUpdateTest { } @BeforeClass - public static void beforeClass() { + public static void beforeClass() throws SQLException { + + XmlCachedDaoTest.dropSchema(); File rootPath = new File(RUNTIME_PATH); File configSrc = new File(CONFIG_SRC); diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java index 70389ca86..d55057582 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java @@ -57,7 +57,7 @@ public class XmlCachedDaoTest extends AbstractModelTest { runtimeMock.startContainer(rootPath); } - private static void dropSchema() throws SQLException { + public static void dropSchema() throws SQLException { String dbVersion = DbSchemaVersionCheck.getExpectedDbVersion(); String sql = DbSchemaVersionCheck.getSql(dbVersion, "drop"); //$NON-NLS-1$ try (Connection connection = DriverManager.getConnection(DB_URL, DB_USERNAME, DB_PASSWORD)) { From 2960fda0793ecb508ceadb9c4ef0704010d71a3d Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 25 Dec 2013 19:05:00 +0100 Subject: [PATCH 14/61] [Major] RuntimeMock now also copies data --- .../dao/test/ObserverUpdateTest.java | 4 +- .../postgresql/dao/test/XmlCachedDaoTest.java | 4 +- .../dao/test/XmlTransactionalDaoTest.java | 57 +++++++++++++++++++ .../config/StrolchConfiguration.xml | 0 .../config/StrolchConfiguration.xml | 27 +++++++++ 5 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 src/test/java/li/strolch/persistence/postgresql/dao/test/XmlTransactionalDaoTest.java rename src/test/resources/{runtime => cachedruntime}/config/StrolchConfiguration.xml (100%) create mode 100644 src/test/resources/transactionalruntime/config/StrolchConfiguration.xml diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index ce20eaee6..aed71ece9 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -46,9 +46,9 @@ import org.junit.Test; */ public class ObserverUpdateTest { - public static final String RUNTIME_PATH = "target/strolchRuntime/"; //$NON-NLS-1$ + public static final String RUNTIME_PATH = "target/observerUpdateStrolchRuntime/"; //$NON-NLS-1$ public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ - public static final String CONFIG_SRC = "src/test/resources/runtime/config"; //$NON-NLS-1$ + public static final String CONFIG_SRC = "src/test/resources/cachedruntime"; //$NON-NLS-1$ protected static RuntimeMock runtimeMock; diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java index d55057582..69aa2d2f9 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java @@ -29,9 +29,9 @@ import org.junit.BeforeClass; public class XmlCachedDaoTest extends AbstractModelTest { - public static final String RUNTIME_PATH = "target/strolchRuntime/"; //$NON-NLS-1$ + public static final String RUNTIME_PATH = "target/cachedStrolchRuntime/"; //$NON-NLS-1$ public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ - public static final String CONFIG_SRC = "src/test/resources/runtime/config"; //$NON-NLS-1$ + public static final String CONFIG_SRC = "src/test/resources/cachedruntime"; //$NON-NLS-1$ private static final String DB_URL = "jdbc:postgresql://localhost/testdb"; //$NON-NLS-1$ private static final String DB_USERNAME = "testuser"; //$NON-NLS-1$ diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlTransactionalDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlTransactionalDaoTest.java new file mode 100644 index 000000000..f0fa14d18 --- /dev/null +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlTransactionalDaoTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql.dao.test; + +import java.io.File; +import java.sql.SQLException; + +import li.strolch.testbase.runtime.AbstractModelTest; +import li.strolch.testbase.runtime.RuntimeMock; + +import org.junit.AfterClass; +import org.junit.BeforeClass; + +public class XmlTransactionalDaoTest extends AbstractModelTest { + + public static final String RUNTIME_PATH = "target/transactionalStrolchRuntime/"; //$NON-NLS-1$ + public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ + public static final String CONFIG_SRC = "src/test/resources/transactionalruntime"; //$NON-NLS-1$ + + protected static RuntimeMock runtimeMock; + + @Override + protected RuntimeMock getRuntimeMock() { + return runtimeMock; + } + + @BeforeClass + public static void beforeClass() throws SQLException { + + XmlCachedDaoTest.dropSchema(); + + File rootPath = new File(RUNTIME_PATH); + File configSrc = new File(CONFIG_SRC); + runtimeMock = new RuntimeMock(); + runtimeMock.mockRuntime(rootPath, configSrc); + new File(rootPath, DB_STORE_PATH_DIR).mkdir(); + runtimeMock.startContainer(rootPath); + } + + @AfterClass + public static void afterClass() { + runtimeMock.destroyRuntime(); + } +} diff --git a/src/test/resources/runtime/config/StrolchConfiguration.xml b/src/test/resources/cachedruntime/config/StrolchConfiguration.xml similarity index 100% rename from src/test/resources/runtime/config/StrolchConfiguration.xml rename to src/test/resources/cachedruntime/config/StrolchConfiguration.xml diff --git a/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml b/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml new file mode 100644 index 000000000..e7248cfbe --- /dev/null +++ b/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml @@ -0,0 +1,27 @@ + + + + StrolchPersistenceTest + + TRANSACTIONAL + true + + + + PersistenceHandler + li.strolch.persistence.api.PersistenceHandler + li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler + + true + true + jdbc:postgresql://localhost/testdb + testuser + test + + + + ObserverHandler + li.strolch.runtime.observer.ObserverHandler + li.strolch.runtime.observer.DefaultObserverHandler + + \ No newline at end of file From ae630d6ddafe938f33ed54c8ed77142c2db7e6e3 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 25 Dec 2013 22:30:53 +0100 Subject: [PATCH 15/61] [Minor] reorganized classes for Agent into api and impl packages --- .../persistence/postgresql/PostgreSqlPersistenceHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index 950f68c8f..fa226a96b 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -28,8 +28,8 @@ import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.runtime.StrolchConstants; -import li.strolch.runtime.agent.ComponentContainerImpl; -import li.strolch.runtime.agent.StrolchComponent; +import li.strolch.runtime.agent.api.StrolchComponent; +import li.strolch.runtime.agent.impl.ComponentContainerImpl; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.StrolchConfigurationException; import li.strolch.runtime.observer.ObserverHandler; From d83b6a4ea7cb54aedb9af5f2abcbf0c5a359b4e0 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Thu, 26 Dec 2013 00:05:11 +0100 Subject: [PATCH 16/61] [Major] TXs are opened from ElementMap and all methods need a TX now --- .../persistence/postgresql/dao/test/ObserverUpdateTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index aed71ece9..4f24fd470 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -113,13 +113,13 @@ public class ObserverUpdateTest { // create order Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType", new Date(), State.CREATED); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = runtimeMock.getPersistenceHandler().openTx();) { + try (StrolchTransaction tx = runtimeMock.getOrderMap().openTx();) { tx.getOrderDao().save(newOrder); } // create resource Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = runtimeMock.getPersistenceHandler().openTx();) { + try (StrolchTransaction tx = runtimeMock.getResourceMap().openTx();) { tx.getResourceDao().save(newResource); } From 0225cea0f4a346d3901988164ec3014051c055ea Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Thu, 26 Dec 2013 01:12:56 +0100 Subject: [PATCH 17/61] [New] Added doQuery() methods to DAOs and hooked up InMemory querying --- .../persistence/postgresql/PostgreSqlOrderDao.java | 8 ++++++++ .../persistence/postgresql/PostgreSqlResourceDao.java | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java index 6a8ac1a65..026884a3d 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java @@ -23,6 +23,7 @@ import java.sql.SQLException; import java.sql.SQLXML; import java.text.MessageFormat; import java.util.Calendar; +import java.util.List; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; @@ -31,6 +32,7 @@ import javax.xml.transform.sax.SAXResult; import li.strolch.model.Order; import li.strolch.model.Tags; +import li.strolch.model.query.OrderQuery; import li.strolch.model.xml.OrderToSaxVisitor; import li.strolch.model.xml.SimpleStrolchElementListener; import li.strolch.model.xml.XmlModelDefaultHandler; @@ -141,4 +143,10 @@ public class PostgreSqlOrderDao extends PostgresqlDao implements OrderDao order.getLocator(), e.getLocalizedMessage()), e); } } + + @Override + public List doQuery(OrderQuery query) { + // TODO Auto-generated method stub + return null; + } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java index 6b4c0b98d..be4d96f04 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java @@ -21,6 +21,7 @@ import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.SQLXML; import java.text.MessageFormat; +import java.util.List; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; @@ -29,6 +30,7 @@ import javax.xml.transform.sax.SAXResult; import li.strolch.model.Resource; import li.strolch.model.Tags; +import li.strolch.model.query.ResourceQuery; import li.strolch.model.xml.ResourceToSaxVisitor; import li.strolch.model.xml.SimpleStrolchElementListener; import li.strolch.model.xml.XmlModelDefaultHandler; @@ -130,4 +132,10 @@ public class PostgreSqlResourceDao extends PostgresqlDao implements Re resource.getLocator(), e.getLocalizedMessage()), e); } } + + @Override + public List doQuery(ResourceQuery query) { + // TODO Auto-generated method stub + return null; + } } From 2a1e2db5bef2c60d45cc4ad8d244e7ebe6141998 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Fri, 27 Dec 2013 11:02:44 +0100 Subject: [PATCH 18/61] [Bugfix] fixed no suitable driver found in Tomcat7 context It seems the class loader mechanism of Tomcat7 makes problems and the driver is not properly found. A solution is to manually force the loading of the driver, before searching for a driver for a URL --- pom.xml | 1 + .../persistence/postgresql/PostgreSqlPersistenceHandler.java | 3 +++ 2 files changed, 4 insertions(+) diff --git a/pom.xml b/pom.xml index 644f000ef..c71236c9d 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,7 @@ org.postgresql postgresql 9.3-1100-jdbc41 + runtime diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index fa226a96b..6486cda0e 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -62,6 +62,9 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe Driver driver; try { + // server loader does not seem to work in all contexts, thus: + org.postgresql.Driver.getLogLevel(); + driver = DriverManager.getDriver(dbUrl); } catch (SQLException e) { String msg = "Failed to load DB driver for URL {0} due to: {1}"; //$NON-NLS-1$ From 58bc33696aa2c54b9dc65ca8f975473cf4a4e4ba Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Fri, 27 Dec 2013 11:03:15 +0100 Subject: [PATCH 19/61] [Bugfix] fixed no suitable driver found in Tomcat7 context It seems the class loader mechanism of Tomcat7 makes problems and the driver is not properly found. A solution is to manually force the loading of the driver, before searching for a driver for a URL --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index c71236c9d..644f000ef 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,6 @@ org.postgresql postgresql 9.3-1100-jdbc41 - runtime From 61cd1e109690339af7c0580858e4c65503aa0a51 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Fri, 10 Jan 2014 16:50:10 +0100 Subject: [PATCH 20/61] [Major] removed project li.strolch.persistence.api Moved all classes to li.strolch.runtime --- pom.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pom.xml b/pom.xml index 644f000ef..4c9dc05c7 100644 --- a/pom.xml +++ b/pom.xml @@ -40,10 +40,6 @@ li.strolch li.strolch.runtime - - li.strolch - li.strolch.persistence.api - org.postgresql From 64fed84708b2f7d2d689c65298f1c08b941e7887 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Fri, 10 Jan 2014 17:16:55 +0100 Subject: [PATCH 21/61] [Major] renamed project li.strolch.runtime to li.strolch.agent --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4c9dc05c7..ee9df100f 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ li.strolch - li.strolch.runtime + li.strolch.agent From 8c91c1294852f6c26428934779b83146976a83f2 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Fri, 10 Jan 2014 19:10:42 +0100 Subject: [PATCH 22/61] [Major] refactored how transactions are opened Now the ElementMapHandler is the central object and clients do not use access DAOs or the PersistenceHandler anymore. This is now transparent. --- .../postgresql/PostgreSqlPersistenceHandler.java | 7 ++----- .../postgresql/PostgreSqlStrolchTransaction.java | 16 ++++++++-------- .../postgresql/dao/test/ObserverUpdateTest.java | 4 ++-- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index 6486cda0e..9dddef4a7 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -30,6 +30,7 @@ import li.strolch.persistence.api.StrolchTransaction; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.agent.api.StrolchComponent; import li.strolch.runtime.agent.impl.ComponentContainerImpl; +import li.strolch.runtime.agent.impl.StrolchRealm; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.StrolchConfigurationException; import li.strolch.runtime.observer.ObserverHandler; @@ -99,11 +100,7 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe super.start(); } - public StrolchTransaction openTx() { - return openTx(StrolchConstants.DEFAULT_REALM); - } - - public StrolchTransaction openTx(String realm) { + public StrolchTransaction openTx(StrolchRealm realm) { PostgreSqlStrolchTransaction tx = new PostgreSqlStrolchTransaction(realm, this); if (getContainer().hasComponent(ObserverHandler.class)) { tx.setObserverHandler(getContainer().getComponent(ObserverHandler.class)); diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index bc365fdef..ff2561625 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -21,14 +21,15 @@ import java.util.Date; import java.util.Set; import li.strolch.model.StrolchElement; +import li.strolch.persistence.api.AbstractTransaction; import li.strolch.persistence.api.ModificationResult; import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchPersistenceException; -import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.api.TransactionCloseStrategy; import li.strolch.persistence.api.TransactionResult; import li.strolch.persistence.api.TransactionState; +import li.strolch.runtime.agent.impl.StrolchRealm; import li.strolch.runtime.observer.ObserverHandler; import org.slf4j.Logger; @@ -36,11 +37,10 @@ import org.slf4j.LoggerFactory; import ch.eitchnet.utils.helper.StringHelper; -public class PostgreSqlStrolchTransaction implements StrolchTransaction { +public class PostgreSqlStrolchTransaction extends AbstractTransaction { private static final Logger logger = LoggerFactory.getLogger(PostgreSqlStrolchTransaction.class); private PostgreSqlPersistenceHandler persistenceHandler; - private String realm; private TransactionCloseStrategy closeStrategy; private ObserverHandler observerHandler; @@ -54,10 +54,10 @@ public class PostgreSqlStrolchTransaction implements StrolchTransaction { private TransactionResult txResult; private boolean open; - public PostgreSqlStrolchTransaction(String realm, PostgreSqlPersistenceHandler persistenceHandler) { + public PostgreSqlStrolchTransaction(StrolchRealm realm, PostgreSqlPersistenceHandler persistenceHandler) { + super(realm); this.startTime = System.nanoTime(); this.startTimeDate = new Date(); - this.realm = realm; this.persistenceHandler = persistenceHandler; this.suppressUpdates = false; this.closeStrategy = TransactionCloseStrategy.COMMIT; @@ -152,7 +152,7 @@ public class PostgreSqlStrolchTransaction implements StrolchTransaction { this.txResult.setStartTime(this.startTimeDate); this.txResult.setTxDuration(txDuration); this.txResult.setCloseDuration(closeDuration); - this.txResult.setRealm(this.realm); + this.txResult.setRealm(getRealm().getRealm()); StringBuilder sb = new StringBuilder(); sb.append("TX was completed after "); //$NON-NLS-1$ @@ -201,7 +201,7 @@ public class PostgreSqlStrolchTransaction implements StrolchTransaction { this.txResult.setStartTime(this.startTimeDate); this.txResult.setTxDuration(txDuration); this.txResult.setCloseDuration(closeDuration); - this.txResult.setRealm(this.realm); + this.txResult.setRealm(getRealm().getRealm()); } @Override @@ -233,7 +233,7 @@ public class PostgreSqlStrolchTransaction implements StrolchTransaction { */ Connection getConnection() { if (this.connection == null) { - this.connection = this.persistenceHandler.getConnection(this.realm); + this.connection = this.persistenceHandler.getConnection(getRealm().getRealm()); } return this.connection; } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index 4f24fd470..6b8c6b665 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -113,13 +113,13 @@ public class ObserverUpdateTest { // create order Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType", new Date(), State.CREATED); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = runtimeMock.getOrderMap().openTx();) { + try (StrolchTransaction tx = runtimeMock.getDefaultRealm().openTx();) { tx.getOrderDao().save(newOrder); } // create resource Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = runtimeMock.getResourceMap().openTx();) { + try (StrolchTransaction tx = runtimeMock.getDefaultRealm().openTx();) { tx.getResourceDao().save(newResource); } From 6bb341964ed8e5778c2ea23e9a360f31ec0432ee Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Fri, 10 Jan 2014 23:23:17 +0100 Subject: [PATCH 23/61] [Major] moved the package li.strolch.runtime.agent to li.strolch.agent --- .../postgresql/PostgreSqlPersistenceHandler.java | 6 +++--- .../postgresql/PostgreSqlStrolchTransaction.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index 9dddef4a7..82ef9ff2d 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -23,14 +23,14 @@ import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; +import li.strolch.agent.api.StrolchComponent; +import li.strolch.agent.impl.ComponentContainerImpl; +import li.strolch.agent.impl.StrolchRealm; import li.strolch.persistence.api.DbConnectionInfo; import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.runtime.StrolchConstants; -import li.strolch.runtime.agent.api.StrolchComponent; -import li.strolch.runtime.agent.impl.ComponentContainerImpl; -import li.strolch.runtime.agent.impl.StrolchRealm; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.StrolchConfigurationException; import li.strolch.runtime.observer.ObserverHandler; diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index ff2561625..2ad5f7104 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -20,6 +20,7 @@ import java.sql.SQLException; import java.util.Date; import java.util.Set; +import li.strolch.agent.impl.StrolchRealm; import li.strolch.model.StrolchElement; import li.strolch.persistence.api.AbstractTransaction; import li.strolch.persistence.api.ModificationResult; @@ -29,7 +30,6 @@ import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.TransactionCloseStrategy; import li.strolch.persistence.api.TransactionResult; import li.strolch.persistence.api.TransactionState; -import li.strolch.runtime.agent.impl.StrolchRealm; import li.strolch.runtime.observer.ObserverHandler; import org.slf4j.Logger; From 21c5eaf78f2a612ba208248977aa8902fe725aa0 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Sat, 11 Jan 2014 17:55:56 +0100 Subject: [PATCH 24/61] [Major] Implemented CACHED mode This lead to refactoring of other code: - removed get*Dao() from StrolchTransaction - added StrolchTransaction.getPersistenceHandler() - removed unused variables in TransactionalElementMap - this lead to removal of constructors in subclasses - added ComponentContainer.getDataStoreMode() - added ElementMap.addAll(), removeAll() and updateAll() methods - implemented in all ElementMap implementations --- .../PostgreSqlPersistenceHandler.java | 12 ++++++++++ .../PostgreSqlStrolchTransaction.java | 23 ++++++++++--------- .../dao/test/ObserverUpdateTest.java | 4 ++-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index 82ef9ff2d..081127842 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -27,7 +27,9 @@ import li.strolch.agent.api.StrolchComponent; import li.strolch.agent.impl.ComponentContainerImpl; import li.strolch.agent.impl.StrolchRealm; import li.strolch.persistence.api.DbConnectionInfo; +import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.PersistenceHandler; +import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.runtime.StrolchConstants; @@ -127,4 +129,14 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe throw new StrolchPersistenceException(msg, e); } } + + @Override + public OrderDao getOrderDao(StrolchTransaction tx) { + return ((PostgreSqlStrolchTransaction) tx).getOrderDao(); + } + + @Override + public ResourceDao getResourceDao(StrolchTransaction tx) { + return ((PostgreSqlStrolchTransaction) tx).getResourceDao(); + } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index 2ad5f7104..63397562d 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -25,6 +25,7 @@ import li.strolch.model.StrolchElement; import li.strolch.persistence.api.AbstractTransaction; import li.strolch.persistence.api.ModificationResult; import li.strolch.persistence.api.OrderDao; +import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.TransactionCloseStrategy; @@ -102,15 +103,12 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { this.txResult = new TransactionResult(); try { - if (this.orderDao != null) { + if (this.orderDao != null) this.orderDao.commit(this.txResult); - } - - if (this.resourceDao != null) { + if (this.resourceDao != null) this.resourceDao.commit(this.txResult); - } - - this.connection.commit(); + if (this.connection != null) + this.connection.commit(); this.txResult.setState(TransactionState.COMMITTED); @@ -214,15 +212,13 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { return this.open; } - @Override - public OrderDao getOrderDao() { + OrderDao getOrderDao() { if (this.orderDao == null) this.orderDao = new PostgreSqlOrderDao(this); return (OrderDao) this.orderDao; } - @Override - public ResourceDao getResourceDao() { + ResourceDao getResourceDao() { if (this.resourceDao == null) this.resourceDao = new PostgreSqlResourceDao(this); return (ResourceDao) this.resourceDao; @@ -237,4 +233,9 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { } return this.connection; } + + @Override + public PersistenceHandler getPersistenceHandler() { + return this.persistenceHandler; + } } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index 6b8c6b665..a60191878 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -114,13 +114,13 @@ public class ObserverUpdateTest { // create order Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType", new Date(), State.CREATED); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ try (StrolchTransaction tx = runtimeMock.getDefaultRealm().openTx();) { - tx.getOrderDao().save(newOrder); + tx.getOrderMap().add(tx, newOrder); } // create resource Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ try (StrolchTransaction tx = runtimeMock.getDefaultRealm().openTx();) { - tx.getResourceDao().save(newResource); + tx.getResourceMap().add(tx, newResource); } assertEquals(2, observer.results.size()); From 65ece12cedaa73ddd6a99070449f48f76f309d92 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 15 Jan 2014 22:09:45 +0100 Subject: [PATCH 25/61] [New] added querySize() methods to ElementMap --- .../persistence/postgresql/PostgresqlDao.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java index 67bd4496c..f7f6c7f4a 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java @@ -51,6 +51,34 @@ public abstract class PostgresqlDao implements Strolch protected abstract T parseFromXml(String id, String type, SQLXML xml); + @Override + public long querySize() { + String sql = "select count(*) from " + getTableName(); + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + try (ResultSet result = statement.executeQuery()) { + result.next(); + return result.getLong(1); + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); + } + } + + @Override + public long querySize(String type) { + + String sql = "select count(*) from " + getTableName() + " where type = ?"; + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + statement.setString(1, type); + try (ResultSet result = statement.executeQuery()) { + result.next(); + return result.getLong(1); + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); + } + } + @Override public Set queryKeySet() { From d287d864e7351c0e9815218002ca511adb684945 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Thu, 23 Jan 2014 22:01:03 +0100 Subject: [PATCH 26/61] [New] added version info metadata to agent --- pom.xml | 4 ++++ src/main/resources/componentVersion.properties | 6 ++++++ 2 files changed, 10 insertions(+) create mode 100644 src/main/resources/componentVersion.properties diff --git a/pom.xml b/pom.xml index ee9df100f..e9454f9a9 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,10 @@ + + org.codehaus.mojo + buildnumber-maven-plugin + org.apache.maven.plugins maven-eclipse-plugin diff --git a/src/main/resources/componentVersion.properties b/src/main/resources/componentVersion.properties new file mode 100644 index 000000000..1f050160f --- /dev/null +++ b/src/main/resources/componentVersion.properties @@ -0,0 +1,6 @@ +groupId=${project.groupId} +artifactId=${project.artifactId} +artifactVersion=${project.version} +scmRevision=r${buildNumber} +scmBranch=${scmBranch} +buildTimestamp=${buildTimestamp} \ No newline at end of file From 6db4b5ddd0e75ae45f94612e59c8fc6493c89a24 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Thu, 23 Jan 2014 22:52:43 +0100 Subject: [PATCH 27/61] [Project] added Jenkins build badge to README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 544187790..30e37cee1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ li.strolch.persistence.postgresql ======================================================================= -PostgreSQL Persistence Implementation for Strolch +[![Build Status](http://jenkins.eitchnet.ch/buildStatus/icon?job=li.strolch.persistence.postgresql)](http://jenkins.eitchnet.ch/view/strolch/job/li.strolch.persistence.postgresql/) +PostgreSQL Persistence Implementation for Strolch Setup ======================================================================= From de72aa225c242242d87024c708ee5b4befe7c7f4 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Sat, 25 Jan 2014 22:14:41 +0100 Subject: [PATCH 28/61] [Major] changed constructor of StrolchComponent Should have interface ComponentContainer in constructor --- .../strolch/persistence/postgresql/DbConnectionCheck.java | 6 +++--- .../postgresql/PostgreSqlPersistenceHandler.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java b/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java index ee8f5f16e..902e34e67 100644 --- a/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java +++ b/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java @@ -24,12 +24,12 @@ import java.text.MessageFormat; import java.util.Collection; import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import li.strolch.persistence.api.DbConnectionInfo; import li.strolch.runtime.configuration.StrolchConfigurationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * @author Robert von Burg */ diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index 081127842..3c275d69f 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -23,8 +23,8 @@ import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; +import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; -import li.strolch.agent.impl.ComponentContainerImpl; import li.strolch.agent.impl.StrolchRealm; import li.strolch.persistence.api.DbConnectionInfo; import li.strolch.persistence.api.OrderDao; @@ -49,7 +49,7 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe private ComponentConfiguration componentConfiguration; private Map connetionInfoMap; - public PostgreSqlPersistenceHandler(ComponentContainerImpl container, String componentName) { + public PostgreSqlPersistenceHandler(ComponentContainer container, String componentName) { super(container, componentName); } From aa0a7c708968cb60e156eab76ad2328535909c7b Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Thu, 30 Jan 2014 00:21:23 +0100 Subject: [PATCH 29/61] [New] Implemented Export and Import model services and commands --- .../li/strolch/persistence/postgresql/PostgreSqlOrderDao.java | 4 ++-- .../strolch/persistence/postgresql/PostgreSqlResourceDao.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java index 026884a3d..e72cc5c22 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java @@ -35,7 +35,7 @@ import li.strolch.model.Tags; import li.strolch.model.query.OrderQuery; import li.strolch.model.xml.OrderToSaxVisitor; import li.strolch.model.xml.SimpleStrolchElementListener; -import li.strolch.model.xml.XmlModelDefaultHandler; +import li.strolch.model.xml.XmlModelSaxReader; import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.StrolchPersistenceException; @@ -67,7 +67,7 @@ public class PostgreSqlOrderDao extends PostgresqlDao implements OrderDao SimpleStrolchElementListener listener = new SimpleStrolchElementListener(); try (InputStream binaryStream = sqlxml.getBinaryStream()) { SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); - parser.parse(binaryStream, new XmlModelDefaultHandler(listener)); + parser.parse(binaryStream, new XmlModelSaxReader(listener)); } catch (SQLException | IOException | SAXException | ParserConfigurationException e) { throw new StrolchPersistenceException(MessageFormat.format( "Failed to extract Order from sqlxml value for {0} / {1}", id, type)); diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java index be4d96f04..fa5967fba 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java @@ -33,7 +33,7 @@ import li.strolch.model.Tags; import li.strolch.model.query.ResourceQuery; import li.strolch.model.xml.ResourceToSaxVisitor; import li.strolch.model.xml.SimpleStrolchElementListener; -import li.strolch.model.xml.XmlModelDefaultHandler; +import li.strolch.model.xml.XmlModelSaxReader; import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.StrolchPersistenceException; @@ -62,7 +62,7 @@ public class PostgreSqlResourceDao extends PostgresqlDao implements Re SimpleStrolchElementListener listener = new SimpleStrolchElementListener(); try (InputStream binaryStream = sqlxml.getBinaryStream()) { SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); - parser.parse(binaryStream, new XmlModelDefaultHandler(listener)); + parser.parse(binaryStream, new XmlModelSaxReader(listener)); } catch (SQLException | IOException | SAXException | ParserConfigurationException e) { throw new StrolchPersistenceException(MessageFormat.format( "Failed to extract Resource from sqlxml value for {0} / {1}", id, type)); From 3c1988b27d4026e6e6e9a3c4b7b5be5bdd9c1a60 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Thu, 13 Feb 2014 22:21:35 +0100 Subject: [PATCH 30/61] [Minor] there is no getDefaultRealm() method anymore --- .../postgresql/dao/test/ObserverUpdateTest.java | 7 ++++--- .../persistence/postgresql/dao/test/XmlCachedDaoTest.java | 2 +- .../postgresql/dao/test/XmlTransactionalDaoTest.java | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index a60191878..b6784b371 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -33,6 +33,7 @@ import li.strolch.model.StrolchElement; import li.strolch.model.Tags; import li.strolch.persistence.api.ModificationResult; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.observer.Observer; import li.strolch.runtime.observer.ObserverHandler; import li.strolch.testbase.runtime.RuntimeMock; @@ -66,7 +67,7 @@ public class ObserverUpdateTest { runtimeMock = new RuntimeMock(); runtimeMock.mockRuntime(rootPath, configSrc); new File(rootPath, DB_STORE_PATH_DIR).mkdir(); - runtimeMock.startContainer(rootPath); + runtimeMock.startContainer(); } @AfterClass @@ -113,13 +114,13 @@ public class ObserverUpdateTest { // create order Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType", new Date(), State.CREATED); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = runtimeMock.getDefaultRealm().openTx();) { + try (StrolchTransaction tx = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).openTx();) { tx.getOrderMap().add(tx, newOrder); } // create resource Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = runtimeMock.getDefaultRealm().openTx();) { + try (StrolchTransaction tx = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).openTx();) { tx.getResourceMap().add(tx, newResource); } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java index 69aa2d2f9..78231fad3 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java @@ -54,7 +54,7 @@ public class XmlCachedDaoTest extends AbstractModelTest { runtimeMock = new RuntimeMock(); runtimeMock.mockRuntime(rootPath, configSrc); new File(rootPath, DB_STORE_PATH_DIR).mkdir(); - runtimeMock.startContainer(rootPath); + runtimeMock.startContainer(); } public static void dropSchema() throws SQLException { diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlTransactionalDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlTransactionalDaoTest.java index f0fa14d18..d101e681b 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlTransactionalDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlTransactionalDaoTest.java @@ -47,7 +47,7 @@ public class XmlTransactionalDaoTest extends AbstractModelTest { runtimeMock = new RuntimeMock(); runtimeMock.mockRuntime(rootPath, configSrc); new File(rootPath, DB_STORE_PATH_DIR).mkdir(); - runtimeMock.startContainer(rootPath); + runtimeMock.startContainer(); } @AfterClass From 7322894078d164cfc742e5fd0985a7efa0d00c6d Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 17 Feb 2014 22:08:06 +0100 Subject: [PATCH 31/61] [New] Implemented separate DataStoreMode for each StrolchRealm --- .../cachedruntime/config/StrolchConfiguration.xml | 10 +++++++++- .../config/StrolchConfiguration.xml | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/test/resources/cachedruntime/config/StrolchConfiguration.xml b/src/test/resources/cachedruntime/config/StrolchConfiguration.xml index 71989f732..f234cea30 100644 --- a/src/test/resources/cachedruntime/config/StrolchConfiguration.xml +++ b/src/test/resources/cachedruntime/config/StrolchConfiguration.xml @@ -3,10 +3,18 @@ StrolchPersistenceTest - CACHED true + + RealmHandler + li.strolch.agent.api.RealmHandler + li.strolch.agent.impl.DefaultRealmHandler + PersistenceHandler + + TRANSACTIONAL + + PersistenceHandler li.strolch.persistence.api.PersistenceHandler diff --git a/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml b/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml index e7248cfbe..f234cea30 100644 --- a/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml +++ b/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml @@ -3,10 +3,18 @@ StrolchPersistenceTest - TRANSACTIONAL true + + RealmHandler + li.strolch.agent.api.RealmHandler + li.strolch.agent.impl.DefaultRealmHandler + PersistenceHandler + + TRANSACTIONAL + + PersistenceHandler li.strolch.persistence.api.PersistenceHandler From be033f3e35c8932ef26b338200685960637527a9 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 19 Feb 2014 00:11:14 +0100 Subject: [PATCH 32/61] [New] PostgreSqlPersistenceHandler now expects a config for each realm Now each realm which is CACHED or TRANSACTIONAL and thus uses a PersistenceHandler must have a dbUrl, dbUsername and dbPassword configured --- .../postgresql/DbConnectionCheck.java | 1 + .../PostgreSqlPersistenceHandler.java | 43 ++++++++++++++----- .../PostgreSqlStrolchTransaction.java | 13 ++++-- ...lCachedDaoTest.java => CachedDaoTest.java} | 2 +- .../dao/test/ObserverUpdateTest.java | 2 +- ...DaoTest.java => TransactionalDaoTest.java} | 4 +- .../realmtest/config/StrolchConfiguration.xml | 42 ++++++++++++++++++ 7 files changed, 88 insertions(+), 19 deletions(-) rename src/test/java/li/strolch/persistence/postgresql/dao/test/{XmlCachedDaoTest.java => CachedDaoTest.java} (97%) rename src/test/java/li/strolch/persistence/postgresql/dao/test/{XmlTransactionalDaoTest.java => TransactionalDaoTest.java} (94%) create mode 100644 src/test/resources/realmtest/config/StrolchConfiguration.xml diff --git a/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java b/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java index 902e34e67..8fa034e5d 100644 --- a/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java +++ b/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java @@ -48,6 +48,7 @@ public class DbConnectionCheck { public void checkConnections() { Collection values = this.connetionInfoMap.values(); for (DbConnectionInfo connectionInfo : values) { + String url = connectionInfo.getUrl(); String username = connectionInfo.getUsername(); String password = connectionInfo.getPassword(); diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index 3c275d69f..428467bfc 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -15,6 +15,8 @@ */ package li.strolch.persistence.postgresql; +import static ch.eitchnet.utils.helper.StringHelper.DOT; + import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; @@ -22,6 +24,7 @@ import java.sql.SQLException; import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; +import java.util.Set; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; @@ -59,33 +62,51 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe this.componentConfiguration = componentConfiguration; this.connetionInfoMap = new HashMap<>(); - String dbUrl = componentConfiguration.getString(PROP_DB_URL, null); - String username = componentConfiguration.getString(PROP_DB_USERNAME, null); - String password = componentConfiguration.getString(PROP_DB_PASSWORD, null); + Set realmNames = getContainer().getRealmNames(); + for (String realmName : realmNames) { + String dbUrlKey = PROP_DB_URL; + String dbUsernameKey = PROP_DB_USERNAME; + String dbPasswordKey = PROP_DB_PASSWORD; + if (!realmName.equals(StrolchConstants.DEFAULT_REALM)) { + dbUrlKey += DOT + realmName; + dbUsernameKey += DOT + realmName; + dbPasswordKey += DOT + realmName; + } + + String dbUrl = componentConfiguration.getString(dbUrlKey, null); + String username = componentConfiguration.getString(dbUsernameKey, null); + String password = componentConfiguration.getString(dbPasswordKey, null); + + DbConnectionInfo connectionInfo = new DbConnectionInfo(realmName, dbUrl); + connectionInfo.setUsername(username); + connectionInfo.setPassword(password); + + loadDriverForConnection(connectionInfo); + this.connetionInfoMap.put(realmName, connectionInfo); + } + + super.initialize(componentConfiguration); + } + + private void loadDriverForConnection(DbConnectionInfo connectionInfo) { Driver driver; try { // server loader does not seem to work in all contexts, thus: org.postgresql.Driver.getLogLevel(); - driver = DriverManager.getDriver(dbUrl); + driver = DriverManager.getDriver(connectionInfo.getUrl()); } catch (SQLException e) { String msg = "Failed to load DB driver for URL {0} due to: {1}"; //$NON-NLS-1$ - msg = MessageFormat.format(msg, dbUrl, e.getMessage()); + msg = MessageFormat.format(msg, connectionInfo.getUrl(), e.getMessage()); throw new StrolchConfigurationException(msg, e); } - DbConnectionInfo connectionInfo = new DbConnectionInfo(StrolchConstants.DEFAULT_REALM, dbUrl); - connectionInfo.setUsername(username); - connectionInfo.setPassword(password); - this.connetionInfoMap.put(StrolchConstants.DEFAULT_REALM, connectionInfo); - String compliant = driver.jdbcCompliant() ? "" : "non"; //$NON-NLS-1$ //$NON-NLS-2$ String msg = "Using {0} JDBC compliant Driver {1}.{2}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, compliant, driver.getMajorVersion(), driver.getMinorVersion()); logger.info(msg); - super.initialize(componentConfiguration); } @Override diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index 63397562d..99e61830a 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -96,7 +96,7 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { public void autoCloseableCommit() { if (logger.isDebugEnabled()) { - logger.info("Committing TX..."); //$NON-NLS-1$ + logger.info("Committing TX for realm " + getRealmName() + "..."); //$NON-NLS-1$ } long start = System.nanoTime(); @@ -127,13 +127,16 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { long txDuration = end - this.startTime; long closeDuration = end - start; StringBuilder sb = new StringBuilder(); - sb.append("TX has failed after "); //$NON-NLS-1$ + sb.append("TX for realm "); + sb.append(getRealmName()); + sb.append(" has failed after "); //$NON-NLS-1$ sb.append(StringHelper.formatNanoDuration(txDuration)); sb.append(" with close operation taking "); //$NON-NLS-1$ sb.append(StringHelper.formatNanoDuration(closeDuration)); logger.info(sb.toString()); - throw new StrolchPersistenceException("Strolch Transaction failed due to " + e.getMessage(), e); //$NON-NLS-1$ + throw new StrolchPersistenceException( + "Strolch Transaction for realm " + getRealmName() + " failed due to " + e.getMessage(), e); //$NON-NLS-1$ } finally { try { @@ -153,7 +156,9 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { this.txResult.setRealm(getRealm().getRealm()); StringBuilder sb = new StringBuilder(); - sb.append("TX was completed after "); //$NON-NLS-1$ + sb.append("TX for realm "); + sb.append(getRealmName()); + sb.append(" was completed after "); //$NON-NLS-1$ sb.append(StringHelper.formatNanoDuration(txDuration)); sb.append(" with close operation taking "); //$NON-NLS-1$ sb.append(StringHelper.formatNanoDuration(closeDuration)); diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java similarity index 97% rename from src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java rename to src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java index 78231fad3..d07f272b9 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlCachedDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java @@ -27,7 +27,7 @@ import li.strolch.testbase.runtime.RuntimeMock; import org.junit.AfterClass; import org.junit.BeforeClass; -public class XmlCachedDaoTest extends AbstractModelTest { +public class CachedDaoTest extends AbstractModelTest { public static final String RUNTIME_PATH = "target/cachedStrolchRuntime/"; //$NON-NLS-1$ public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index b6784b371..a2d204681 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -60,7 +60,7 @@ public class ObserverUpdateTest { @BeforeClass public static void beforeClass() throws SQLException { - XmlCachedDaoTest.dropSchema(); + CachedDaoTest.dropSchema(); File rootPath = new File(RUNTIME_PATH); File configSrc = new File(CONFIG_SRC); diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlTransactionalDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalDaoTest.java similarity index 94% rename from src/test/java/li/strolch/persistence/postgresql/dao/test/XmlTransactionalDaoTest.java rename to src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalDaoTest.java index d101e681b..fe788760d 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/XmlTransactionalDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalDaoTest.java @@ -24,7 +24,7 @@ import li.strolch.testbase.runtime.RuntimeMock; import org.junit.AfterClass; import org.junit.BeforeClass; -public class XmlTransactionalDaoTest extends AbstractModelTest { +public class TransactionalDaoTest extends AbstractModelTest { public static final String RUNTIME_PATH = "target/transactionalStrolchRuntime/"; //$NON-NLS-1$ public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ @@ -40,7 +40,7 @@ public class XmlTransactionalDaoTest extends AbstractModelTest { @BeforeClass public static void beforeClass() throws SQLException { - XmlCachedDaoTest.dropSchema(); + CachedDaoTest.dropSchema(); File rootPath = new File(RUNTIME_PATH); File configSrc = new File(CONFIG_SRC); diff --git a/src/test/resources/realmtest/config/StrolchConfiguration.xml b/src/test/resources/realmtest/config/StrolchConfiguration.xml new file mode 100644 index 000000000..6dd922435 --- /dev/null +++ b/src/test/resources/realmtest/config/StrolchConfiguration.xml @@ -0,0 +1,42 @@ + + + + StrolchPersistenceTest + + true + + + + RealmHandler + li.strolch.agent.api.RealmHandler + li.strolch.agent.impl.DefaultRealmHandler + PersistenceHandler + + first, second + TRANSACTIONAL + TRANSACTIONAL + + + + PersistenceHandler + li.strolch.persistence.api.PersistenceHandler + li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler + + true + true + + jdbc:postgresql://localhost/testdb + testuser + test + + jdbc:postgresql://localhost/testdb + testuser + test + + + + ObserverHandler + li.strolch.runtime.observer.ObserverHandler + li.strolch.runtime.observer.DefaultObserverHandler + + \ No newline at end of file From ecfb2c8e00974f77abfc7a28c2fb3c2e0875be2e Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 19 Feb 2014 00:53:00 +0100 Subject: [PATCH 33/61] [New] added realm testing with different connections --- .../PostgreSqlStrolchTransaction.java | 10 +- .../postgresql/dao/test/CachedDaoTest.java | 14 +-- .../dao/test/ObserverUpdateTest.java | 3 +- .../postgresql/dao/test/RealmTest.java | 118 ++++++++++++++++++ .../dao/test/TransactionalDaoTest.java | 7 +- .../realmtest/config/StrolchConfiguration.xml | 8 +- 6 files changed, 143 insertions(+), 17 deletions(-) create mode 100644 src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index 99e61830a..17b2739b1 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -139,10 +139,12 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { "Strolch Transaction for realm " + getRealmName() + " failed due to " + e.getMessage(), e); //$NON-NLS-1$ } finally { - try { - this.connection.close(); - } catch (Exception e) { - logger.error("Failed to close connection due to " + e.getMessage(), e); //$NON-NLS-1$ + if (this.connection != null) { + try { + this.connection.close(); + } catch (Exception e) { + logger.error("Failed to close connection due to " + e.getMessage(), e); //$NON-NLS-1$ + } } } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java index d07f272b9..f689524ed 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java @@ -33,12 +33,12 @@ public class CachedDaoTest extends AbstractModelTest { public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ public static final String CONFIG_SRC = "src/test/resources/cachedruntime"; //$NON-NLS-1$ - private static final String DB_URL = "jdbc:postgresql://localhost/testdb"; //$NON-NLS-1$ - private static final String DB_USERNAME = "testuser"; //$NON-NLS-1$ - private static final String DB_PASSWORD = "test"; //$NON-NLS-1$ + public static final String DB_URL = "jdbc:postgresql://localhost/testdb"; //$NON-NLS-1$ + public static final String DB_USERNAME = "testuser"; //$NON-NLS-1$ + public static final String DB_PASSWORD = "test"; //$NON-NLS-1$ protected static RuntimeMock runtimeMock; - + @Override protected RuntimeMock getRuntimeMock() { return runtimeMock; @@ -47,7 +47,7 @@ public class CachedDaoTest extends AbstractModelTest { @BeforeClass public static void beforeClass() throws SQLException { - dropSchema(); + dropSchema(DB_URL, DB_USERNAME, DB_PASSWORD); File rootPath = new File(RUNTIME_PATH); File configSrc = new File(CONFIG_SRC); @@ -57,10 +57,10 @@ public class CachedDaoTest extends AbstractModelTest { runtimeMock.startContainer(); } - public static void dropSchema() throws SQLException { + public static void dropSchema(String dbUrl, String dbUsername, String dbPassword) throws SQLException { String dbVersion = DbSchemaVersionCheck.getExpectedDbVersion(); String sql = DbSchemaVersionCheck.getSql(dbVersion, "drop"); //$NON-NLS-1$ - try (Connection connection = DriverManager.getConnection(DB_URL, DB_USERNAME, DB_PASSWORD)) { + try (Connection connection = DriverManager.getConnection(dbUrl, dbUsername, dbPassword)) { connection.prepareStatement(sql).execute(); } } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index a2d204681..6b26990a7 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -41,6 +41,7 @@ import li.strolch.testbase.runtime.RuntimeMock; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.*; /** * @author Robert von Burg @@ -60,7 +61,7 @@ public class ObserverUpdateTest { @BeforeClass public static void beforeClass() throws SQLException { - CachedDaoTest.dropSchema(); + dropSchema(DB_URL, DB_USERNAME, DB_PASSWORD); File rootPath = new File(RUNTIME_PATH); File configSrc = new File(CONFIG_SRC); diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java new file mode 100644 index 000000000..682f25dbe --- /dev/null +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java @@ -0,0 +1,118 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql.dao.test; + +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.dropSchema; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.io.File; +import java.sql.SQLException; + +import li.strolch.agent.impl.DataStoreMode; +import li.strolch.agent.impl.StrolchRealm; +import li.strolch.model.ModelGenerator; +import li.strolch.model.Resource; +import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.testbase.runtime.AbstractModelTest; +import li.strolch.testbase.runtime.RuntimeMock; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class RealmTest extends AbstractModelTest { + + public static final String RUNTIME_PATH = "target/realmTest/"; //$NON-NLS-1$ + public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ + public static final String CONFIG_SRC = "src/test/resources/realmTest"; //$NON-NLS-1$ + + protected static RuntimeMock runtimeMock; + + @Override + protected RuntimeMock getRuntimeMock() { + return runtimeMock; + } + + @BeforeClass + public static void beforeClass() throws SQLException { + + dropSchema("jdbc:postgresql://localhost/testdb1", "testuser1", "test"); + dropSchema("jdbc:postgresql://localhost/testdb2", "testuser2", "test"); + + File rootPath = new File(RUNTIME_PATH); + File configSrc = new File(CONFIG_SRC); + runtimeMock = new RuntimeMock(); + runtimeMock.mockRuntime(rootPath, configSrc); + new File(rootPath, DB_STORE_PATH_DIR).mkdir(); + runtimeMock.startContainer(); + } + + @Before + public void before() { + this.realmName = "second"; + } + + @Test + public void testDifferentRealms() { + + String expectedId1 = "@realmTestId1"; + String expectedId2 = "@realmTestId2"; + String type = "Bla"; + + { + StrolchRealm firstRealm = runtimeMock.getRealm("first"); + assertEquals(DataStoreMode.TRANSACTIONAL, firstRealm.getMode()); + Resource expectedRes1 = ModelGenerator.createResource(expectedId1, "Bla bla", type); + try (StrolchTransaction tx = firstRealm.openTx()) { + tx.getResourceMap().add(tx, expectedRes1); + } + + try (StrolchTransaction tx = firstRealm.openTx()) { + Resource res = tx.getResourceMap().getBy(tx, type, expectedId1); + assertEquals("Should find object previously added in same realm!", expectedRes1, res); + } + } + + { + StrolchRealm secondRealm = runtimeMock.getRealm("second"); + assertEquals(DataStoreMode.TRANSACTIONAL, secondRealm.getMode()); + Resource expectedRes2 = ModelGenerator.createResource(expectedId2, "Bla bla", type); + try (StrolchTransaction tx = secondRealm.openTx()) { + tx.getResourceMap().add(tx, expectedRes2); + } + + try (StrolchTransaction tx = secondRealm.openTx()) { + Resource res = tx.getResourceMap().getBy(tx, type, expectedId2); + assertEquals("Should find object previously added in same realm!", expectedRes2, res); + } + } + + { + StrolchRealm secondRealm = runtimeMock.getRealm("second"); + try (StrolchTransaction tx = secondRealm.openTx()) { + Resource res = tx.getResourceMap().getBy(tx, type, expectedId1); + assertNull("Should not find object added in differenct realm!", res); + } + } + } + + @AfterClass + public static void afterClass() { + runtimeMock.destroyRuntime(); + } +} diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalDaoTest.java index fe788760d..331b50e40 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalDaoTest.java @@ -15,6 +15,11 @@ */ package li.strolch.persistence.postgresql.dao.test; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_PASSWORD; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_URL; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_USERNAME; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.dropSchema; + import java.io.File; import java.sql.SQLException; @@ -40,7 +45,7 @@ public class TransactionalDaoTest extends AbstractModelTest { @BeforeClass public static void beforeClass() throws SQLException { - CachedDaoTest.dropSchema(); + dropSchema(DB_URL, DB_USERNAME, DB_PASSWORD); File rootPath = new File(RUNTIME_PATH); File configSrc = new File(CONFIG_SRC); diff --git a/src/test/resources/realmtest/config/StrolchConfiguration.xml b/src/test/resources/realmtest/config/StrolchConfiguration.xml index 6dd922435..617535181 100644 --- a/src/test/resources/realmtest/config/StrolchConfiguration.xml +++ b/src/test/resources/realmtest/config/StrolchConfiguration.xml @@ -25,12 +25,12 @@ true true - jdbc:postgresql://localhost/testdb - testuser + jdbc:postgresql://localhost/testdb1 + testuser1 test - jdbc:postgresql://localhost/testdb - testuser + jdbc:postgresql://localhost/testdb2 + testuser2 test From a7a4d4f5dd1c43ab3318f98773357a5abad09c1e Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 19 Feb 2014 01:03:48 +0100 Subject: [PATCH 34/61] [Minor] fixed broken test due to typo --- .../li/strolch/persistence/postgresql/dao/test/RealmTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java index 682f25dbe..45cb75c2b 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java @@ -37,9 +37,9 @@ import org.junit.Test; public class RealmTest extends AbstractModelTest { - public static final String RUNTIME_PATH = "target/realmTest/"; //$NON-NLS-1$ + public static final String RUNTIME_PATH = "target/realmtest/"; //$NON-NLS-1$ public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ - public static final String CONFIG_SRC = "src/test/resources/realmTest"; //$NON-NLS-1$ + public static final String CONFIG_SRC = "src/test/resources/realmtest"; //$NON-NLS-1$ protected static RuntimeMock runtimeMock; From 902a1530433b44d175d4b430fc2eac84a4c78470 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 24 Feb 2014 21:48:59 +0100 Subject: [PATCH 35/61] [New] Implemented locking for Strolch elements Also cleaned up hierarchy of StrolchTransaction by moving up everything into AbstractTransaction as made sense and added special delegation methods for the actual commit() and rollback() ind the concrete implementations. --- .../PostgreSqlPersistenceHandler.java | 2 +- .../PostgreSqlStrolchTransaction.java | 156 +----------------- .../postgresql/dao/test/RealmTest.java | 2 +- 3 files changed, 7 insertions(+), 153 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index 428467bfc..b1ee9956f 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -28,7 +28,7 @@ import java.util.Set; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; -import li.strolch.agent.impl.StrolchRealm; +import li.strolch.agent.api.StrolchRealm; import li.strolch.persistence.api.DbConnectionInfo; import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.PersistenceHandler; diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index 17b2739b1..196fe69e9 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -16,128 +16,40 @@ package li.strolch.persistence.postgresql; import java.sql.Connection; -import java.sql.SQLException; -import java.util.Date; -import java.util.Set; -import li.strolch.agent.impl.StrolchRealm; -import li.strolch.model.StrolchElement; +import li.strolch.agent.api.StrolchRealm; import li.strolch.persistence.api.AbstractTransaction; -import li.strolch.persistence.api.ModificationResult; import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.ResourceDao; -import li.strolch.persistence.api.StrolchPersistenceException; -import li.strolch.persistence.api.TransactionCloseStrategy; import li.strolch.persistence.api.TransactionResult; -import li.strolch.persistence.api.TransactionState; -import li.strolch.runtime.observer.ObserverHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.eitchnet.utils.helper.StringHelper; - public class PostgreSqlStrolchTransaction extends AbstractTransaction { private static final Logger logger = LoggerFactory.getLogger(PostgreSqlStrolchTransaction.class); private PostgreSqlPersistenceHandler persistenceHandler; - private TransactionCloseStrategy closeStrategy; - private ObserverHandler observerHandler; - private boolean suppressUpdates; - private PostgresqlDao orderDao; private PostgresqlDao resourceDao; private Connection connection; - private long startTime; - private Date startTimeDate; - private TransactionResult txResult; - private boolean open; public PostgreSqlStrolchTransaction(StrolchRealm realm, PostgreSqlPersistenceHandler persistenceHandler) { super(realm); - this.startTime = System.nanoTime(); - this.startTimeDate = new Date(); this.persistenceHandler = persistenceHandler; - this.suppressUpdates = false; - this.closeStrategy = TransactionCloseStrategy.COMMIT; - } - - /** - * @param observerHandler - * the observerHandler to set - */ - public void setObserverHandler(ObserverHandler observerHandler) { - this.observerHandler = observerHandler; - } - - /** - * @param suppressUpdates - * the suppressUpdates to set - */ - public void setSuppressUpdates(boolean suppressUpdates) { - this.suppressUpdates = suppressUpdates; - } - - /** - * @return the suppressUpdates - */ - public boolean isSuppressUpdates() { - return this.suppressUpdates; } @Override - public void setCloseStrategy(TransactionCloseStrategy closeStrategy) { - this.closeStrategy = closeStrategy; - } - - @Override - public void autoCloseableCommit() { - - if (logger.isDebugEnabled()) { - logger.info("Committing TX for realm " + getRealmName() + "..."); //$NON-NLS-1$ - } - - long start = System.nanoTime(); - this.txResult = new TransactionResult(); - + protected void commit(TransactionResult txResult) throws Exception { try { if (this.orderDao != null) - this.orderDao.commit(this.txResult); + this.orderDao.commit(txResult); if (this.resourceDao != null) - this.resourceDao.commit(this.txResult); + this.resourceDao.commit(txResult); if (this.connection != null) this.connection.commit(); - - this.txResult.setState(TransactionState.COMMITTED); - - } catch (Exception e) { - - if (this.connection != null) { - try { - this.connection.rollback(); - } catch (SQLException e1) { - logger.error("Failed to rollback transation due to " + e.getMessage(), e); //$NON-NLS-1$ - } - } - - this.txResult.setState(TransactionState.FAILED); - long end = System.nanoTime(); - long txDuration = end - this.startTime; - long closeDuration = end - start; - StringBuilder sb = new StringBuilder(); - sb.append("TX for realm "); - sb.append(getRealmName()); - sb.append(" has failed after "); //$NON-NLS-1$ - sb.append(StringHelper.formatNanoDuration(txDuration)); - sb.append(" with close operation taking "); //$NON-NLS-1$ - sb.append(StringHelper.formatNanoDuration(closeDuration)); - logger.info(sb.toString()); - - throw new StrolchPersistenceException( - "Strolch Transaction for realm " + getRealmName() + " failed due to " + e.getMessage(), e); //$NON-NLS-1$ - } finally { if (this.connection != null) { try { @@ -147,47 +59,13 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { } } } - - long end = System.nanoTime(); - long txDuration = end - this.startTime; - long closeDuration = end - start; - - this.txResult.setStartTime(this.startTimeDate); - this.txResult.setTxDuration(txDuration); - this.txResult.setCloseDuration(closeDuration); - this.txResult.setRealm(getRealm().getRealm()); - - StringBuilder sb = new StringBuilder(); - sb.append("TX for realm "); - sb.append(getRealmName()); - sb.append(" was completed after "); //$NON-NLS-1$ - sb.append(StringHelper.formatNanoDuration(txDuration)); - sb.append(" with close operation taking "); //$NON-NLS-1$ - sb.append(StringHelper.formatNanoDuration(closeDuration)); - logger.info(sb.toString()); - - if (!this.suppressUpdates && this.observerHandler != null) { - - Set keys = this.txResult.getKeys(); - for (String key : keys) { - ModificationResult modificationResult = this.txResult.getModificationResult(key); - - this.observerHandler.add(key, modificationResult. getCreated()); - this.observerHandler.update(key, modificationResult. getUpdated()); - this.observerHandler.remove(key, modificationResult. getDeleted()); - } - } } @Override - public void autoCloseableRollback() { - long start = System.nanoTime(); - + protected void rollback(TransactionResult txResult) throws Exception { if (this.connection != null) { try { this.connection.rollback(); - } catch (SQLException e) { - throw new StrolchPersistenceException("Strolch Transaction failed due to " + e.getMessage(), e); //$NON-NLS-1$ } finally { try { this.connection.close(); @@ -196,27 +74,6 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { } } } - - long end = System.nanoTime(); - long txDuration = end - this.startTime; - long closeDuration = end - start; - - this.txResult = new TransactionResult(); - this.txResult.setState(TransactionState.ROLLED_BACK); - this.txResult.setStartTime(this.startTimeDate); - this.txResult.setTxDuration(txDuration); - this.txResult.setCloseDuration(closeDuration); - this.txResult.setRealm(getRealm().getRealm()); - } - - @Override - public void close() throws StrolchPersistenceException { - this.closeStrategy.close(this); - } - - @Override - public boolean isOpen() { - return this.open; } OrderDao getOrderDao() { @@ -231,9 +88,6 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { return (ResourceDao) this.resourceDao; } - /** - * @return - */ Connection getConnection() { if (this.connection == null) { this.connection = this.persistenceHandler.getConnection(getRealm().getRealm()); diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java index 45cb75c2b..47f60b199 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java @@ -22,8 +22,8 @@ import static org.junit.Assert.assertNull; import java.io.File; import java.sql.SQLException; +import li.strolch.agent.api.StrolchRealm; import li.strolch.agent.impl.DataStoreMode; -import li.strolch.agent.impl.StrolchRealm; import li.strolch.model.ModelGenerator; import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; From 911a92ad5e3b0fc904b7d515137aa376a6e565d8 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 25 Feb 2014 21:19:10 +0100 Subject: [PATCH 36/61] [Minor] Added update count checking when executing INSERT, UPDATE, DEL --- .../postgresql/PostgreSqlOrderDao.java | 14 +++++++-- .../postgresql/PostgreSqlResourceDao.java | 14 +++++++-- .../PostgreSqlStrolchTransaction.java | 29 +++++++++---------- .../persistence/postgresql/PostgresqlDao.java | 7 ++++- 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java index e72cc5c22..af99372bd 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java @@ -107,7 +107,12 @@ public class PostgreSqlOrderDao extends PostgresqlDao implements OrderDao SQLXML sqlxml = createSqlXml(order, preparedStatement); preparedStatement.setSQLXML(6, sqlxml); try { - preparedStatement.execute(); + int modCount = preparedStatement.executeUpdate(); + if (modCount != 1) { + String msg = "Expected to save 1 element with id {0} but SQL statement modified {1} elements!"; + msg = MessageFormat.format(msg, order.getId(), modCount); + throw new StrolchPersistenceException(msg); + } } finally { sqlxml.free(); } @@ -133,7 +138,12 @@ public class PostgreSqlOrderDao extends PostgresqlDao implements OrderDao SQLXML sqlxml = createSqlXml(order, preparedStatement); preparedStatement.setSQLXML(5, sqlxml); try { - preparedStatement.execute(); + int modCount = preparedStatement.executeUpdate(); + if (modCount != 1) { + String msg = "Expected to update 1 element with id {0} but SQL statement modified {1} elements!"; + msg = MessageFormat.format(msg, order.getId(), modCount); + throw new StrolchPersistenceException(msg); + } } finally { sqlxml.free(); } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java index fa5967fba..4f24d24a7 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java @@ -99,7 +99,12 @@ public class PostgreSqlResourceDao extends PostgresqlDao implements Re SQLXML sqlxml = createSqlXml(res, preparedStatement); preparedStatement.setSQLXML(4, sqlxml); try { - preparedStatement.execute(); + int modCount = preparedStatement.executeUpdate(); + if (modCount != 1) { + String msg = "Expected to save 1 element with id {0} but SQL statement modified {1} elements!"; + msg = MessageFormat.format(msg, res.getId(), modCount); + throw new StrolchPersistenceException(msg); + } } finally { sqlxml.free(); } @@ -122,7 +127,12 @@ public class PostgreSqlResourceDao extends PostgresqlDao implements Re SQLXML sqlxml = createSqlXml(resource, preparedStatement); preparedStatement.setSQLXML(3, sqlxml); try { - preparedStatement.execute(); + int modCount = preparedStatement.executeUpdate(); + if (modCount != 1) { + String msg = "Expected to update 1 element with id {0} but SQL statement modified {1} elements!"; + msg = MessageFormat.format(msg, resource.getId(), modCount); + throw new StrolchPersistenceException(msg); + } } finally { sqlxml.free(); } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index 196fe69e9..16f3a975b 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -43,22 +43,19 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { @Override protected void commit(TransactionResult txResult) throws Exception { - try { - if (this.orderDao != null) - this.orderDao.commit(txResult); - if (this.resourceDao != null) - this.resourceDao.commit(txResult); - if (this.connection != null) - this.connection.commit(); - } finally { - if (this.connection != null) { - try { - this.connection.close(); - } catch (Exception e) { - logger.error("Failed to close connection due to " + e.getMessage(), e); //$NON-NLS-1$ - } - } - } + + // first perform DAOs + if (this.orderDao != null) + this.orderDao.commit(txResult); + if (this.resourceDao != null) + this.resourceDao.commit(txResult); + + // then commit the SQL connection + if (this.connection != null) + this.connection.commit(); + + // and close the connection, but not catching, as otherwise we can't rollback in exception case + this.connection.close(); } @Override diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java index f7f6c7f4a..a2214308a 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java @@ -289,7 +289,12 @@ public abstract class PostgresqlDao implements Strolch try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { preparedStatement.setString(1, element.getId()); - preparedStatement.execute(); + int modCount = preparedStatement.executeUpdate(); + if (modCount != 1) { + String msg = "Expected to delete 1 element with id {0} but SQL statement modified {1} elements!"; + msg = MessageFormat.format(msg, element.getId(), modCount); + throw new StrolchPersistenceException(msg); + } } catch (SQLException e) { throw new StrolchPersistenceException(MessageFormat.format("Failed to update Order {0} due to {2}", From 17bf200d3c8c46cfaaf223407e34cb71a6d9894b Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 3 Mar 2014 18:41:26 +0100 Subject: [PATCH 37/61] [Minor] cleaned up exception message --- .../postgresql/DbSchemaVersionCheck.java | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java b/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java index 29242d65f..e93c6c896 100644 --- a/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java +++ b/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java @@ -76,7 +76,7 @@ public class DbSchemaVersionCheck { String username = connectionInfo.getUsername(); String password = connectionInfo.getPassword(); - logger.info("Checking Schema version for realm " + realm + "..."); + logger.info(MessageFormat.format("[{0}] Checking Schema version...", realm)); try (Connection con = DriverManager.getConnection(url, username, password); Statement st = con.createStatement();) { @@ -84,9 +84,8 @@ public class DbSchemaVersionCheck { String expectedDbVersion = getExpectedDbVersion(); // first see if we have any schema - String checkSchemaExistsSql = MessageFormat - .format("select table_schema, table_name, table_type from information_schema.tables where table_name=''{0}'';", - PROP_DB_VERSION); + String msg = "select table_schema, table_name, table_type from information_schema.tables where table_name=''{0}'';"; + String checkSchemaExistsSql = MessageFormat.format(msg, PROP_DB_VERSION); try (ResultSet rs = st.executeQuery(checkSchemaExistsSql)) { if (!rs.next()) { createSchema(realm, expectedDbVersion, st); @@ -110,10 +109,13 @@ public class DbSchemaVersionCheck { } else { String currentVersion = rs.getString(2); if (expectedDbVersion.equals(currentVersion)) { - logger.info("Schema version " + currentVersion + " is the current version. No changes needed."); + String msg = "[{0}] Schema version {1} is the current version. No changes needed."; + msg = MessageFormat.format(msg, realm, currentVersion); + logger.info(msg); } else { - logger.warn("Schema version is not current. Need to upgrade from " + currentVersion + " to " - + expectedDbVersion); + String msg = "[{0}] Schema version is not current. Need to upgrade from {1} to {2}"; + msg = MessageFormat.format(msg, realm, currentVersion, expectedDbVersion); + logger.warn(msg); upgradeSchema(realm, expectedDbVersion, st); } } @@ -127,8 +129,9 @@ public class DbSchemaVersionCheck { MessageFormat.format("Resource file with name {0} does not exist!", RESOURCE_DB_VERSION), stream); dbVersionProps.load(stream); } catch (IOException e) { - throw new StrolchException("Expected resource file " + RESOURCE_DB_VERSION - + " does not exist or is not a valid properties file: " + e.getMessage(), e); + String msg = "Expected resource file {0} does not exist or is not a valid properties file: {1}"; + msg = MessageFormat.format(msg, RESOURCE_DB_VERSION, e.getMessage()); + throw new StrolchException(msg, e); } String dbVersion = dbVersionProps.getProperty(PROP_DB_VERSION); String msg = "Missing property {0} in resource file {1}"; @@ -137,7 +140,7 @@ public class DbSchemaVersionCheck { } public static String getSql(String dbVersion, String type) { - String schemaResourceS = "/db_schema_" + dbVersion + "_" + type + ".sql"; + String schemaResourceS = MessageFormat.format("/db_schema_{0}_{1}.sql", dbVersion, type); try (InputStream stream = DbSchemaVersionCheck.class.getResourceAsStream(schemaResourceS);) { DBC.PRE.assertNotNull( MessageFormat.format("Schema Resource file with name {0} does not exist!", schemaResourceS), stream); @@ -155,11 +158,12 @@ public class DbSchemaVersionCheck { private void createSchema(String realm, String dbVersion, Statement st) { if (!this.allowSchemaCreation) { - throw new StrolchConfigurationException("[" + realm - + "] No schema exists, or is not valid. Schema generation is disabled, thus can not continue!"); + String msg = "[{0}] No schema exists, or is not valid. Schema generation is disabled, thus can not continue!"; + msg = MessageFormat.format(msg, realm); + throw new StrolchConfigurationException(msg); } - logger.info("[" + realm + "] Creating initial schema..."); + logger.info(MessageFormat.format("[{0}] Creating initial schema...", realm)); String sql = getSql(dbVersion, "initial"); try { @@ -169,17 +173,18 @@ public class DbSchemaVersionCheck { throw new StrolchException("Failed to execute schema generation SQL: " + e.getMessage(), e); } - logger.info("[" + realm + "] Successfully created schema for version " + dbVersion); + logger.info(MessageFormat.format("[{0}] Successfully created schema for version {1}", realm, dbVersion)); } private void dropSchema(String realm, String dbVersion, Statement st) { if (!this.allowSchemaDrop) { - throw new StrolchConfigurationException("[" + realm - + "] Dropping Schema is disabled, but is required to upgrade current schema..."); + String msg = "[{0}] Dropping Schema is disabled, but is required to upgrade current schema..."; + msg = MessageFormat.format(msg, realm); + throw new StrolchConfigurationException(msg); } - logger.info("[" + realm + "] Dropping existing schema..."); + logger.info(MessageFormat.format("[{0}] Dropping existing schema...", realm)); String sql = getSql(dbVersion, "drop"); try { From 9555f562fab26c78c3f3edad4e079ed50147beb6 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 3 Mar 2014 18:42:12 +0100 Subject: [PATCH 38/61] [Bugfix] don't check db connection for realms which are transient --- .../postgresql/PostgreSqlPersistenceHandler.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index b1ee9956f..c158762ca 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -65,6 +65,10 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe Set realmNames = getContainer().getRealmNames(); for (String realmName : realmNames) { + StrolchRealm realm = getContainer().getRealm(realmName); + if (realm.getMode().isTransient()) + continue; + String dbUrlKey = PROP_DB_URL; String dbUsernameKey = PROP_DB_USERNAME; String dbPasswordKey = PROP_DB_PASSWORD; @@ -103,8 +107,9 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe } String compliant = driver.jdbcCompliant() ? "" : "non"; //$NON-NLS-1$ //$NON-NLS-2$ - String msg = "Using {0} JDBC compliant Driver {1}.{2}"; //$NON-NLS-1$ - msg = MessageFormat.format(msg, compliant, driver.getMajorVersion(), driver.getMinorVersion()); + String msg = "Realm {0}: Using {1} JDBC compliant Driver {2}.{3}"; //$NON-NLS-1$ + msg = MessageFormat.format(msg, connectionInfo.getRealm(), compliant, driver.getMajorVersion(), + driver.getMinorVersion()); logger.info(msg); } From 692f80fa610fb51a0d3505bc1cec007f8f0a4e4c Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 3 Mar 2014 23:22:55 +0100 Subject: [PATCH 39/61] [Bugfix] Don't close unopened connection When a PostgreSQL transaction is opened without any objects being modified or queried, then the connection won't be opened, thus no need to close it. --- .../postgresql/PostgreSqlStrolchTransaction.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index 16f3a975b..fa4709d26 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -51,11 +51,12 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { this.resourceDao.commit(txResult); // then commit the SQL connection - if (this.connection != null) + if (this.connection != null) { this.connection.commit(); - // and close the connection, but not catching, as otherwise we can't rollback in exception case - this.connection.close(); + // and close the connection, but not catching, as otherwise we can't rollback in exception case + this.connection.close(); + } } @Override From 3b8444894aa62f6db1557f5c9372f7ff1562652e Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Fri, 14 Mar 2014 14:36:53 +0100 Subject: [PATCH 40/61] [Project] fixed urls of projects --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index e9454f9a9..13cc92479 100644 --- a/pom.xml +++ b/pom.xml @@ -15,19 +15,19 @@ li.strolch.persistence.postgresql PostgreSQL Persistence Implementation for Strolch - https://github.com/eitch/li.strolch.persistence.postgresql + https://github.com/eitchnet/li.strolch.persistence.postgresql 2011 Github Issues - https://github.com/eitch/li.strolch.persistence.postgresql/issues + https://github.com/eitchnet/li.strolch.persistence.postgresql/issues - scm:git:https://github.com/eitch/li.strolch.persistence.postgresql.git + scm:git:https://github.com/eitchnet/li.strolch.persistence.postgresql.git scm:git:git@github.com:eitch/li.strolch.persistence.postgresql.git - https://github.com/eitch/li.strolch.persistence.postgresql + https://github.com/eitchnet/li.strolch.persistence.postgresql From 7c0e64808d767fab7fb509dce338143c71784620 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Fri, 13 Jun 2014 17:54:01 +0200 Subject: [PATCH 41/61] [Minor] documenting how to run tests by adding user for postgresql --- README.md | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 30e37cee1..4988ce20f 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,28 @@ Setup $ sudo -u postgres psql postgres postgres=# \password postgres 3. Create the user and DB: - $ sudo su - postgres - postgres=# create user testUser with password 'test'; - postgres=# create database testdb; - postgres=# GRANT ALL PRIVILEGES ON DATABASE testdb to testuser; - postgres=# GRANT CONNECT ON DATABASE testdb TO testuser ; + $ sudo -u postgres psql + $ postgres=# + create user testUser with password 'test'; + create database testdb; + GRANT ALL PRIVILEGES ON DATABASE testdb to testuser; + GRANT CONNECT ON DATABASE testdb TO testuser ; + + # For tests: + create user testUser with password 'test'; + create database testdb; + GRANT ALL PRIVILEGES ON DATABASE testdb to testuser; + GRANT CONNECT ON DATABASE testdb TO testuser ; + + create user testuser1 with password 'test'; + create database testdb1; + GRANT ALL PRIVILEGES ON DATABASE testdb1 to testuser1; + GRANT CONNECT ON DATABASE testdb1 TO testuser1 ; + + create user testuser2 with password 'test'; + create database testdb2; + GRANT ALL PRIVILEGES ON DATABASE testdb2 to testuser2; + GRANT CONNECT ON DATABASE testdb2 TO testuser2 ; 4. Added new component, setting properties for PostgreSQL DB: From 7b6ad39060bb2b20147041822f330ba2c65d89e8 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Thu, 31 Jul 2014 16:12:00 +0200 Subject: [PATCH 42/61] [Major] added new methods ElementMap.removeAll() --- .../persistence/postgresql/PostgresqlDao.java | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java index a2214308a..2337b83e5 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java @@ -274,6 +274,36 @@ public abstract class PostgresqlDao implements Strolch }); } + @Override + public long removeAll() { + + final long toRemove = querySize(); + + this.commands.add(new DaoCommand() { + @Override + public void doComand(ModificationResult modificationResult) { + internalRemoveAll(toRemove); + } + }); + + return toRemove; + } + + @Override + public long removeAllBy(final String type) { + + final long toRemove = querySize(type); + + this.commands.add(new DaoCommand() { + @Override + public void doComand(ModificationResult modificationResult) { + internalRemoveAllBy(toRemove, type); + } + }); + + return toRemove; + } + /** * @param element */ @@ -297,11 +327,44 @@ public abstract class PostgresqlDao implements Strolch } } catch (SQLException e) { - throw new StrolchPersistenceException(MessageFormat.format("Failed to update Order {0} due to {2}", + throw new StrolchPersistenceException(MessageFormat.format("Failed to remove {0} due to {2}", element.getLocator(), e.getLocalizedMessage()), e); } } + protected void internalRemoveAll(final long toRemove) { + String sql = "delete from " + getTableName(); + try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { + int modCount = preparedStatement.executeUpdate(); + if (modCount != toRemove) { + String msg = "Expected to delete {0} elements but SQL statement removed {1} elements!"; + msg = MessageFormat.format(msg, toRemove, modCount); + throw new StrolchPersistenceException(msg); + } + + } catch (SQLException e) { + throw new StrolchPersistenceException(MessageFormat.format("Failed to remove all elements due to {0}", + e.getLocalizedMessage()), e); + } + } + + protected void internalRemoveAllBy(final long toRemove, String type) { + String sql = "delete from " + getTableName() + " where type = ?"; + try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { + preparedStatement.setString(1, type); + int modCount = preparedStatement.executeUpdate(); + if (modCount != toRemove) { + String msg = "Expected to delete {0} elements of type {1} but SQL statement removed {2} elements!"; + msg = MessageFormat.format(msg, toRemove, type, modCount); + throw new StrolchPersistenceException(msg); + } + + } catch (SQLException e) { + throw new StrolchPersistenceException(MessageFormat.format( + "Failed to remove all elements of type {0} due to {1}", type, e.getLocalizedMessage()), e); + } + } + void commit(TransactionResult txResult) { ModificationResult modificationResult = new ModificationResult(getClassName()); txResult.addModificationResult(modificationResult); From 5623f27f2d6685b3aa34a4024c8b52835d920f18 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 4 Aug 2014 11:47:51 +0200 Subject: [PATCH 43/61] [New] Implemented StrolchDao.hasElement() --- .../persistence/postgresql/PostgresqlDao.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java index 2337b83e5..3318f6161 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java @@ -51,6 +51,27 @@ public abstract class PostgresqlDao implements Strolch protected abstract T parseFromXml(String id, String type, SQLXML xml); + @Override + public boolean hasElement(String type, String id) { + String sql = "select count(*) from " + getTableName() + " where type = ?"; + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + statement.setString(1, type); + try (ResultSet result = statement.executeQuery()) { + result.next(); + long numberOfElements = result.getLong(1); + if (numberOfElements == 0) + return false; + if (numberOfElements == 1) + return true; + + String msg = MessageFormat.format("Non unique number of elements with type {0} and id {1}", type, id); + throw new StrolchPersistenceException(msg); + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); + } + } + @Override public long querySize() { String sql = "select count(*) from " + getTableName(); @@ -66,7 +87,6 @@ public abstract class PostgresqlDao implements Strolch @Override public long querySize(String type) { - String sql = "select count(*) from " + getTableName() + " where type = ?"; try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); From 72d5bdce9eb5710c57ecf815180cc408efe8037f Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 4 Aug 2014 15:36:25 +0200 Subject: [PATCH 44/61] [Bugfix] fixed wrong implementation of Dao.hasElement() --- .../java/li/strolch/persistence/postgresql/PostgresqlDao.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java index 3318f6161..12c3c4644 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java @@ -53,9 +53,10 @@ public abstract class PostgresqlDao implements Strolch @Override public boolean hasElement(String type, String id) { - String sql = "select count(*) from " + getTableName() + " where type = ?"; + String sql = "select count(*) from " + getTableName() + " where type = ? and id = ?"; try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); + statement.setString(2, id); try (ResultSet result = statement.executeQuery()) { result.next(); long numberOfElements = result.getLong(1); From cd15808bde0e2eaded8a2f98213378302edf0a02 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 6 Aug 2014 18:42:50 +0200 Subject: [PATCH 45/61] [New] Moved *Visitor transformations in query into query method This is better than keeping the Visitor in the instance of the query, where it might be to early to instantiate it. --- .../li/strolch/persistence/postgresql/PostgreSqlOrderDao.java | 3 ++- .../strolch/persistence/postgresql/PostgreSqlResourceDao.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java index af99372bd..245c91da3 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java @@ -31,6 +31,7 @@ import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.sax.SAXResult; import li.strolch.model.Order; +import li.strolch.model.OrderVisitor; import li.strolch.model.Tags; import li.strolch.model.query.OrderQuery; import li.strolch.model.xml.OrderToSaxVisitor; @@ -155,7 +156,7 @@ public class PostgreSqlOrderDao extends PostgresqlDao implements OrderDao } @Override - public List doQuery(OrderQuery query) { + public List doQuery(OrderQuery query, OrderVisitor orderVisitor) { // TODO Auto-generated method stub return null; } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java index 4f24d24a7..d0455a956 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java @@ -29,6 +29,7 @@ import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.sax.SAXResult; import li.strolch.model.Resource; +import li.strolch.model.ResourceVisitor; import li.strolch.model.Tags; import li.strolch.model.query.ResourceQuery; import li.strolch.model.xml.ResourceToSaxVisitor; @@ -144,7 +145,7 @@ public class PostgreSqlResourceDao extends PostgresqlDao implements Re } @Override - public List doQuery(ResourceQuery query) { + public List doQuery(ResourceQuery query, ResourceVisitor resourceVisitor) { // TODO Auto-generated method stub return null; } From 0b68acc80308e11fa71eeeb4c3826fec0d5ca058 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 13 Aug 2014 16:06:09 +0200 Subject: [PATCH 46/61] [Major] Refactored StrolchConfiguration.xml to use environments Now the agent requires an environment parameter to start, and the configuration of that environment is used to load different sections of the configuration file --- .../config/StrolchConfiguration.xml | 66 ++++++++-------- .../realmtest/config/StrolchConfiguration.xml | 76 ++++++++++--------- .../config/StrolchConfiguration.xml | 66 ++++++++-------- 3 files changed, 107 insertions(+), 101 deletions(-) diff --git a/src/test/resources/cachedruntime/config/StrolchConfiguration.xml b/src/test/resources/cachedruntime/config/StrolchConfiguration.xml index f234cea30..b030e7899 100644 --- a/src/test/resources/cachedruntime/config/StrolchConfiguration.xml +++ b/src/test/resources/cachedruntime/config/StrolchConfiguration.xml @@ -1,35 +1,37 @@ - - StrolchPersistenceTest - - true - - - - RealmHandler - li.strolch.agent.api.RealmHandler - li.strolch.agent.impl.DefaultRealmHandler - PersistenceHandler - - TRANSACTIONAL - - - - PersistenceHandler - li.strolch.persistence.api.PersistenceHandler - li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler - - true - true - jdbc:postgresql://localhost/testdb - testuser - test - - - - ObserverHandler - li.strolch.runtime.observer.ObserverHandler - li.strolch.runtime.observer.DefaultObserverHandler - + + + StrolchPersistenceTest + + true + + + + RealmHandler + li.strolch.agent.api.RealmHandler + li.strolch.agent.impl.DefaultRealmHandler + PersistenceHandler + + TRANSACTIONAL + + + + PersistenceHandler + li.strolch.persistence.api.PersistenceHandler + li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler + + true + true + jdbc:postgresql://localhost/testdb + testuser + test + + + + ObserverHandler + li.strolch.runtime.observer.ObserverHandler + li.strolch.runtime.observer.DefaultObserverHandler + + \ No newline at end of file diff --git a/src/test/resources/realmtest/config/StrolchConfiguration.xml b/src/test/resources/realmtest/config/StrolchConfiguration.xml index 617535181..6367afe64 100644 --- a/src/test/resources/realmtest/config/StrolchConfiguration.xml +++ b/src/test/resources/realmtest/config/StrolchConfiguration.xml @@ -1,42 +1,44 @@ - - StrolchPersistenceTest - - true - - - - RealmHandler - li.strolch.agent.api.RealmHandler - li.strolch.agent.impl.DefaultRealmHandler - PersistenceHandler - - first, second - TRANSACTIONAL - TRANSACTIONAL - - - - PersistenceHandler - li.strolch.persistence.api.PersistenceHandler - li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler - - true - true + + + StrolchPersistenceTest + + true + + + + RealmHandler + li.strolch.agent.api.RealmHandler + li.strolch.agent.impl.DefaultRealmHandler + PersistenceHandler + + first, second + TRANSACTIONAL + TRANSACTIONAL + + + + PersistenceHandler + li.strolch.persistence.api.PersistenceHandler + li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler + + true + true - jdbc:postgresql://localhost/testdb1 - testuser1 - test + jdbc:postgresql://localhost/testdb1 + testuser1 + test - jdbc:postgresql://localhost/testdb2 - testuser2 - test - - - - ObserverHandler - li.strolch.runtime.observer.ObserverHandler - li.strolch.runtime.observer.DefaultObserverHandler - + jdbc:postgresql://localhost/testdb2 + testuser2 + test + + + + ObserverHandler + li.strolch.runtime.observer.ObserverHandler + li.strolch.runtime.observer.DefaultObserverHandler + + \ No newline at end of file diff --git a/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml b/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml index f234cea30..b030e7899 100644 --- a/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml +++ b/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml @@ -1,35 +1,37 @@ - - StrolchPersistenceTest - - true - - - - RealmHandler - li.strolch.agent.api.RealmHandler - li.strolch.agent.impl.DefaultRealmHandler - PersistenceHandler - - TRANSACTIONAL - - - - PersistenceHandler - li.strolch.persistence.api.PersistenceHandler - li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler - - true - true - jdbc:postgresql://localhost/testdb - testuser - test - - - - ObserverHandler - li.strolch.runtime.observer.ObserverHandler - li.strolch.runtime.observer.DefaultObserverHandler - + + + StrolchPersistenceTest + + true + + + + RealmHandler + li.strolch.agent.api.RealmHandler + li.strolch.agent.impl.DefaultRealmHandler + PersistenceHandler + + TRANSACTIONAL + + + + PersistenceHandler + li.strolch.persistence.api.PersistenceHandler + li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler + + true + true + jdbc:postgresql://localhost/testdb + testuser + test + + + + ObserverHandler + li.strolch.runtime.observer.ObserverHandler + li.strolch.runtime.observer.DefaultObserverHandler + + \ No newline at end of file From 4432a141ceedec92a64b308942121af4f954b9a5 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 13 Aug 2014 23:37:52 +0200 Subject: [PATCH 47/61] [Project] added resource filtering for componentVersion.properties --- pom.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pom.xml b/pom.xml index 13cc92479..759c20567 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,15 @@ + + + src/main/resources + true + + **/componentVersion.properties + + + org.codehaus.mojo From bfc27cebaf2640944ae298f2cc66a04fb782ada0 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 13 Aug 2014 23:52:57 +0200 Subject: [PATCH 48/61] [Project] added resource filtering for componentVersion.properties --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index 759c20567..d9bba601c 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,13 @@ **/componentVersion.properties + + src/main/resources + false + + **/componentVersion.properties + + From 9ca21c29f8bb78858490a3b27a96486ab14e3a7a Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Sat, 23 Aug 2014 20:49:52 +0200 Subject: [PATCH 49/61] [New] Implemented opt-in audit trail in Strolch The audit trail has its own map on the Realm and a trail is written by realm at the end of the transaction. You can write your own audit trail using tx.getAuditTrail(). Enable the audit trail by setting the realm configuration value 'enableAuditTrail'. --- .../postgresql/DbSchemaVersionCheck.java | 3 +- .../postgresql/PostgreSqlAuditDao.java | 326 ++++++++++++++++++ .../PostgreSqlPersistenceHandler.java | 12 +- .../PostgreSqlStrolchTransaction.java | 37 +- .../persistence/postgresql/PostgresqlDao.java | 3 - src/main/resources/db_schema_0.2.0_drop.sql | 8 + .../resources/db_schema_0.2.0_initial.sql | 61 ++++ src/main/resources/db_version.properties | 2 +- .../dao/test/ObserverUpdateTest.java | 15 +- .../postgresql/dao/test/RealmTest.java | 16 +- .../cachedruntime/config/PrivilegeConfig.xml | 30 ++ .../cachedruntime/config/PrivilegeModel.xml | 36 ++ .../config/StrolchConfiguration.xml | 10 + .../realmtest/config/PrivilegeConfig.xml | 30 ++ .../realmtest/config/PrivilegeModel.xml | 36 ++ .../realmtest/config/StrolchConfiguration.xml | 11 + .../config/PrivilegeConfig.xml | 30 ++ .../config/PrivilegeModel.xml | 36 ++ .../config/StrolchConfiguration.xml | 10 + 19 files changed, 686 insertions(+), 26 deletions(-) create mode 100644 src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java create mode 100644 src/main/resources/db_schema_0.2.0_drop.sql create mode 100644 src/main/resources/db_schema_0.2.0_initial.sql create mode 100644 src/test/resources/cachedruntime/config/PrivilegeConfig.xml create mode 100644 src/test/resources/cachedruntime/config/PrivilegeModel.xml create mode 100644 src/test/resources/realmtest/config/PrivilegeConfig.xml create mode 100644 src/test/resources/realmtest/config/PrivilegeModel.xml create mode 100644 src/test/resources/transactionalruntime/config/PrivilegeConfig.xml create mode 100644 src/test/resources/transactionalruntime/config/PrivilegeModel.xml diff --git a/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java b/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java index e93c6c896..7ad6bc8cd 100644 --- a/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java +++ b/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java @@ -76,7 +76,7 @@ public class DbSchemaVersionCheck { String username = connectionInfo.getUsername(); String password = connectionInfo.getPassword(); - logger.info(MessageFormat.format("[{0}] Checking Schema version...", realm)); + logger.info(MessageFormat.format("[{0}] Checking Schema version for: {1}@{2}", realm, username, url)); try (Connection con = DriverManager.getConnection(url, username, password); Statement st = con.createStatement();) { @@ -202,5 +202,4 @@ public class DbSchemaVersionCheck { dropSchema(realm, dbVersion, st); createSchema(realm, dbVersion, st); } - } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java new file mode 100644 index 000000000..8884eedae --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java @@ -0,0 +1,326 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import li.strolch.model.audit.AccessType; +import li.strolch.model.audit.Audit; +import li.strolch.model.audit.AuditQuery; +import li.strolch.model.audit.AuditVisitor; +import li.strolch.persistence.api.AuditDao; +import li.strolch.persistence.api.StrolchPersistenceException; +import ch.eitchnet.utils.collections.DateRange; + +/** + * @author Robert von Burg + */ +public class PostgreSqlAuditDao implements AuditDao { + + private PostgreSqlStrolchTransaction tx; + + /** + * @param postgreSqlStrolchTransaction + */ + public PostgreSqlAuditDao(PostgreSqlStrolchTransaction postgreSqlStrolchTransaction) { + this.tx = postgreSqlStrolchTransaction; + } + + @Override + public boolean hasElement(String type, Long id) { + String sql = "select count(*) from audits where element_type = ? and id = ?"; + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + + statement.setString(1, type); + statement.setLong(2, id); + + try (ResultSet result = statement.executeQuery()) { + result.next(); + long numberOfElements = result.getLong(1); + if (numberOfElements == 0) + return false; + if (numberOfElements == 1) + return true; + + String msg = MessageFormat.format("Non unique number of elements with type {0} and id {1}", type, id); + throw new StrolchPersistenceException(msg); + } + + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); + } + } + + @Override + public long querySize(DateRange dateRange) { + String sql = "select count(*) from audits where date between ? and ?"; + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + + statement.setDate(1, new Date(dateRange.getFromDate().getTime()), Calendar.getInstance()); + statement.setDate(2, new Date(dateRange.getToDate().getTime()), Calendar.getInstance()); + + try (ResultSet result = statement.executeQuery()) { + result.next(); + return result.getLong(1); + } + + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); + } + } + + @Override + public long querySize(String type, DateRange dateRange) { + String sql = "select count(*) from audits where element_type = ? and date between ? and ?"; + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + + statement.setString(1, type); + statement.setDate(2, new Date(dateRange.getFromDate().getTime()), Calendar.getInstance()); + statement.setDate(3, new Date(dateRange.getToDate().getTime()), Calendar.getInstance()); + + try (ResultSet result = statement.executeQuery()) { + result.next(); + return result.getLong(1); + } + + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); + } + } + + @Override + public Set queryTypes() { + Set keySet = new HashSet<>(); + + String sql = "select distinct element_type from audits"; + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + try (ResultSet result = statement.executeQuery()) { + while (result.next()) { + keySet.add(result.getString("element_type")); + } + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + } + + return keySet; + } + + @Override + public Audit queryBy(String type, Long id) { + + String sql = "select id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type from audits where element_type = ? and id = ?"; + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + + statement.setString(1, type); + statement.setLong(2, id); + + try (ResultSet result = statement.executeQuery()) { + if (!result.next()) { + return null; + } + Audit audit = auditFrom(result); + if (result.next()) + throw new StrolchPersistenceException("Non unique result for query: " + sql); + return audit; + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + } + } + + @Override + public List queryAll(String type, DateRange dateRange) { + List list = new ArrayList<>(); + String sql = "select id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type from audits where element_type = ? and date between ? and ?"; + try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { + + statement.setString(1, type); + statement.setDate(2, new Date(dateRange.getFromDate().getTime()), Calendar.getInstance()); + statement.setDate(3, new Date(dateRange.getToDate().getTime()), Calendar.getInstance()); + + try (ResultSet result = statement.executeQuery()) { + while (result.next()) { + list.add(auditFrom(result)); + } + } + + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + } + + return list; + } + + @Override + public void save(Audit audit) { + String sql = "insert into audits (id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?::access_type)"; + try (PreparedStatement preparedStatement = tx.getConnection().prepareStatement(sql)) { + + setAuditFields(audit, preparedStatement); + + int count = preparedStatement.executeUpdate(); + if (count != 1) { + throw new StrolchPersistenceException(MessageFormat.format( + "Expected to create 1 record, but created {0} for audit {2}", count, audit.getId())); + } + + } catch (SQLException e) { + throw new StrolchPersistenceException(MessageFormat.format("Failed to update Audit {0} due to {1}", audit, + e.getLocalizedMessage()), e); + } + } + + @Override + public void saveAll(List audits) { + for (Audit audit : audits) { + save(audit); + } + } + + @Override + public void update(Audit audit) { + String sql = "update audits set id = ?, username = ?, firstname = ?, lastname = ?, date = ?, element_type = ?, element_accessed = ?, new_version = ?, action = ?, access_type = ?::access_type where id = ?"; + try (PreparedStatement preparedStatement = tx.getConnection().prepareStatement(sql)) { + + setAuditFields(audit, preparedStatement); + preparedStatement.setLong(11, audit.getId()); + + int count = preparedStatement.executeUpdate(); + if (count != 1) { + throw new StrolchPersistenceException(MessageFormat.format( + "Expected to update 1 record, but updated {0} for audit {2}", count, audit.getId())); + } + + } catch (SQLException e) { + throw new StrolchPersistenceException(MessageFormat.format("Failed to update Audit {0} due to {1}", audit, + e.getLocalizedMessage()), e); + } + } + + @Override + public void updateAll(List audits) { + for (Audit audit : audits) { + update(audit); + } + } + + @Override + public void remove(Audit audit) { + String sql = "delete from audits where id = ?"; + try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { + + preparedStatement.setLong(1, audit.getId()); + + int count = preparedStatement.executeUpdate(); + if (count != 1) { + String msg = "Expected to delete 1 audit with id {0} but deleted {1} elements!"; + msg = MessageFormat.format(msg, audit.getId(), count); + throw new StrolchPersistenceException(msg); + } + + } catch (SQLException e) { + throw new StrolchPersistenceException(MessageFormat.format("Failed to remove {0} due to {2}", + audit.getId(), e.getLocalizedMessage()), e); + } + } + + @Override + public void removeAll(List audits) { + for (Audit audit : audits) { + remove(audit); + } + } + + @Override + public long removeAll(String type, DateRange dateRange) { + String sql = "delete from audits where element_type = ? and date between ? and ?"; + try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { + + preparedStatement.setString(1, type); + preparedStatement.setDate(2, new Date(dateRange.getFromDate().getTime()), Calendar.getInstance()); + preparedStatement.setDate(3, new Date(dateRange.getToDate().getTime()), Calendar.getInstance()); + + int modCount = preparedStatement.executeUpdate(); + return modCount; + + } catch (SQLException e) { + throw new StrolchPersistenceException(MessageFormat.format("Failed to remove all elements due to {0}", + e.getLocalizedMessage()), e); + } + } + + @Override + public List doQuery(AuditQuery query, AuditVisitor auditVisitor) { + // TODO Auto-generated method stub + return null; + } + + private void setAuditFields(Audit audit, PreparedStatement ps) throws SQLException { + + // 1 id = ?, + // 2 username = ?, + // 3 firstname = ?, + // 4 lastname = ?, + // 5 date = ?, + // 6 element_type = ?, + // 7 element_accessed = ?, + // 8 new_version = ?, + // 9 action = ?, + // 10 access_type = ?::access_type + + ps.setLong(1, audit.getId()); + ps.setString(2, audit.getUsername()); + ps.setString(3, audit.getFirstname()); + ps.setString(4, audit.getLastname()); + ps.setDate(5, new Date(audit.getDate().getTime()), Calendar.getInstance()); + ps.setString(6, audit.getElementType()); + ps.setString(7, audit.getElementAccessed()); + + if (audit.getNewVersion() == null) + ps.setDate(8, null); + else + ps.setDate(8, new Date(audit.getNewVersion().getTime()), Calendar.getInstance()); + + ps.setString(9, audit.getAction()); + ps.setString(10, audit.getAccessType().name()); + } + + private Audit auditFrom(ResultSet resultSet) throws SQLException { + + Audit audit = new Audit(); + audit.setId(resultSet.getLong(1)); + audit.setUsername(resultSet.getString(2)); + audit.setFirstname(resultSet.getString(3)); + audit.setLastname(resultSet.getString(4)); + audit.setDate(resultSet.getDate(5)); + audit.setElementType(resultSet.getString(6)); + audit.setElementAccessed(resultSet.getString(7)); + audit.setNewVersion(resultSet.getDate(8)); + audit.setAction(resultSet.getString(9)); + audit.setAccessType(AccessType.valueOf(resultSet.getString(10))); + return audit; + } +} diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index c158762ca..8e18e58f4 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -29,6 +29,7 @@ import java.util.Set; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; import li.strolch.agent.api.StrolchRealm; +import li.strolch.persistence.api.AuditDao; import li.strolch.persistence.api.DbConnectionInfo; import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.PersistenceHandler; @@ -39,6 +40,7 @@ import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.StrolchConfigurationException; import li.strolch.runtime.observer.ObserverHandler; +import ch.eitchnet.privilege.model.Certificate; /** * @author Robert von Burg @@ -128,8 +130,9 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe super.start(); } - public StrolchTransaction openTx(StrolchRealm realm) { - PostgreSqlStrolchTransaction tx = new PostgreSqlStrolchTransaction(realm, this); + @Override + public StrolchTransaction openTx(StrolchRealm realm, Certificate certificate, String action) { + PostgreSqlStrolchTransaction tx = new PostgreSqlStrolchTransaction(realm, certificate, action, this); if (getContainer().hasComponent(ObserverHandler.class)) { tx.setObserverHandler(getContainer().getComponent(ObserverHandler.class)); } @@ -165,4 +168,9 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe public ResourceDao getResourceDao(StrolchTransaction tx) { return ((PostgreSqlStrolchTransaction) tx).getResourceDao(); } + + @Override + public AuditDao getAuditDao(StrolchTransaction tx) { + return ((PostgreSqlStrolchTransaction) tx).getAuditDao(); + } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index fa4709d26..d8026176d 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -19,6 +19,7 @@ import java.sql.Connection; import li.strolch.agent.api.StrolchRealm; import li.strolch.persistence.api.AbstractTransaction; +import li.strolch.persistence.api.AuditDao; import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.ResourceDao; @@ -27,6 +28,8 @@ import li.strolch.persistence.api.TransactionResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ch.eitchnet.privilege.model.Certificate; + public class PostgreSqlStrolchTransaction extends AbstractTransaction { private static final Logger logger = LoggerFactory.getLogger(PostgreSqlStrolchTransaction.class); @@ -34,15 +37,17 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { private PostgresqlDao orderDao; private PostgresqlDao resourceDao; + private AuditDao auditDao; private Connection connection; - public PostgreSqlStrolchTransaction(StrolchRealm realm, PostgreSqlPersistenceHandler persistenceHandler) { - super(realm); + public PostgreSqlStrolchTransaction(StrolchRealm realm, Certificate certificate, String action, + PostgreSqlPersistenceHandler persistenceHandler) { + super(realm, certificate, action); this.persistenceHandler = persistenceHandler; } @Override - protected void commit(TransactionResult txResult) throws Exception { + protected void writeChanges(TransactionResult txResult) throws Exception { // first perform DAOs if (this.orderDao != null) @@ -50,13 +55,7 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { if (this.resourceDao != null) this.resourceDao.commit(txResult); - // then commit the SQL connection - if (this.connection != null) { - this.connection.commit(); - - // and close the connection, but not catching, as otherwise we can't rollback in exception case - this.connection.close(); - } + // don't commit the connection, this is done in postCommit when we close the connection } @Override @@ -74,6 +73,14 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { } } + @Override + protected void commit() throws Exception { + if (this.connection != null) { + this.connection.commit(); + this.connection.close(); + } + } + OrderDao getOrderDao() { if (this.orderDao == null) this.orderDao = new PostgreSqlOrderDao(this); @@ -86,6 +93,15 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { return (ResourceDao) this.resourceDao; } + /** + * @return + */ + public AuditDao getAuditDao() { + if (this.auditDao == null) + this.auditDao = new PostgreSqlAuditDao(this); + return (AuditDao) this.auditDao; + } + Connection getConnection() { if (this.connection == null) { this.connection = this.persistenceHandler.getConnection(getRealm().getRealm()); @@ -97,4 +113,5 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { public PersistenceHandler getPersistenceHandler() { return this.persistenceHandler; } + } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java index 12c3c4644..163da325e 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java @@ -37,9 +37,6 @@ public abstract class PostgresqlDao implements Strolch protected PostgreSqlStrolchTransaction tx; protected List commands; - /** - * @param tx - */ public PostgresqlDao(PostgreSqlStrolchTransaction tx) { this.tx = tx; this.commands = new ArrayList<>(); diff --git a/src/main/resources/db_schema_0.2.0_drop.sql b/src/main/resources/db_schema_0.2.0_drop.sql new file mode 100644 index 000000000..467a2c3ed --- /dev/null +++ b/src/main/resources/db_schema_0.2.0_drop.sql @@ -0,0 +1,8 @@ + +DROP TABLE IF EXISTS resources; +DROP TABLE IF EXISTS orders; +DROP TABLE IF EXISTS audits; +DROP TABLE IF EXISTS db_version; + +DROP TYPE IF EXISTS order_state; +DROP TYPE IF EXISTS access_type; diff --git a/src/main/resources/db_schema_0.2.0_initial.sql b/src/main/resources/db_schema_0.2.0_initial.sql new file mode 100644 index 000000000..dd7a298be --- /dev/null +++ b/src/main/resources/db_schema_0.2.0_initial.sql @@ -0,0 +1,61 @@ + +-- DB_VERSION +CREATE TABLE IF NOT EXISTS db_version ( + id SERIAL PRIMARY KEY, + version varchar(255), + description varchar(255), + created timestamp with time zone +); + +-- RESOURCES +CREATE TABLE IF NOT EXISTS resources ( + id varchar(255) PRIMARY KEY, + name VARCHAR(255), + type VARCHAR(255), + asxml xml +); + +-- ORDERS +CREATE TYPE order_state AS ENUM ('CREATED', 'OPEN', 'EXECUTION', 'CLOSED'); + +CREATE TABLE IF NOT EXISTS orders ( + id varchar(255) PRIMARY KEY, + name VARCHAR(255), + type VARCHAR(255), + state order_state, + date timestamp with time zone, + asxml xml +); + +-- AUDITS +CREATE TYPE access_type AS ENUM ('READ', 'CREATE', 'UPDATE', 'DELETE'); +CREATE TABLE IF NOT EXISTS audits ( + id bigint PRIMARY KEY, + username VARCHAR(255) NOT NULL, + firstname VARCHAR(255) NOT NULL, + lastname VARCHAR(255) NOT NULL, + date timestamp with time zone NOT NULL, + + element_type VARCHAR(255) NOT NULL, + element_accessed VARCHAR(255) NOT NULL, + new_version timestamp with time zone, + + action VARCHAR(255) NOT NULL, + access_type access_type NOT NULL +); + +-- set version +INSERT INTO db_version + (version, description, created) +values( + '0.1.0', + 'Initial schema version', + CURRENT_TIMESTAMP +); +INSERT INTO db_version + (version, description, created) +values( + '0.2.0', + 'Added new table for audits', + CURRENT_TIMESTAMP +); diff --git a/src/main/resources/db_version.properties b/src/main/resources/db_version.properties index d0ef82ac6..ac24bcc3c 100644 --- a/src/main/resources/db_version.properties +++ b/src/main/resources/db_version.properties @@ -1,2 +1,2 @@ # Property file defining what the currently expected version is supposed to be -db_version=0.1.0 \ No newline at end of file +db_version=0.2.0 \ No newline at end of file diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index 6b26990a7..9af319ff7 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -17,6 +17,10 @@ package li.strolch.persistence.postgresql.dao.test; import static li.strolch.model.ModelGenerator.createOrder; import static li.strolch.model.ModelGenerator.createResource; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_PASSWORD; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_URL; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_USERNAME; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.dropSchema; import static org.junit.Assert.assertEquals; import java.io.File; @@ -36,12 +40,14 @@ import li.strolch.persistence.api.StrolchTransaction; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.observer.Observer; import li.strolch.runtime.observer.ObserverHandler; +import li.strolch.runtime.privilege.PrivilegeHandler; import li.strolch.testbase.runtime.RuntimeMock; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.*; + +import ch.eitchnet.privilege.model.Certificate; /** * @author Robert von Burg @@ -113,15 +119,18 @@ public class ObserverUpdateTest { runtimeMock.getContainer().getComponent(ObserverHandler.class).registerObserver(Tags.ORDER, observer); runtimeMock.getContainer().getComponent(ObserverHandler.class).registerObserver(Tags.RESOURCE, observer); + PrivilegeHandler privilegeHandler = runtimeMock.getAgent().getContainer().getPrivilegeHandler(); + Certificate certificate = privilegeHandler.authenticate("test", "test".getBytes()); + // create order Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType", new Date(), State.CREATED); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).openTx();) { + try (StrolchTransaction tx = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).openTx(certificate, "test")) { tx.getOrderMap().add(tx, newOrder); } // create resource Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).openTx();) { + try (StrolchTransaction tx = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).openTx(certificate, "test");) { tx.getResourceMap().add(tx, newResource); } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java index 47f60b199..78156edf9 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java @@ -27,6 +27,7 @@ import li.strolch.agent.impl.DataStoreMode; import li.strolch.model.ModelGenerator; import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.runtime.privilege.PrivilegeHandler; import li.strolch.testbase.runtime.AbstractModelTest; import li.strolch.testbase.runtime.RuntimeMock; @@ -35,6 +36,8 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import ch.eitchnet.privilege.model.Certificate; + public class RealmTest extends AbstractModelTest { public static final String RUNTIME_PATH = "target/realmtest/"; //$NON-NLS-1$ @@ -74,15 +77,18 @@ public class RealmTest extends AbstractModelTest { String expectedId2 = "@realmTestId2"; String type = "Bla"; + PrivilegeHandler privilegeHandler = runtimeMock.getAgent().getContainer().getPrivilegeHandler(); + Certificate certificate = privilegeHandler.authenticate("test", "test".getBytes()); + { StrolchRealm firstRealm = runtimeMock.getRealm("first"); assertEquals(DataStoreMode.TRANSACTIONAL, firstRealm.getMode()); Resource expectedRes1 = ModelGenerator.createResource(expectedId1, "Bla bla", type); - try (StrolchTransaction tx = firstRealm.openTx()) { + try (StrolchTransaction tx = firstRealm.openTx(certificate, "test")) { tx.getResourceMap().add(tx, expectedRes1); } - try (StrolchTransaction tx = firstRealm.openTx()) { + try (StrolchTransaction tx = firstRealm.openTx(certificate, "test")) { Resource res = tx.getResourceMap().getBy(tx, type, expectedId1); assertEquals("Should find object previously added in same realm!", expectedRes1, res); } @@ -92,11 +98,11 @@ public class RealmTest extends AbstractModelTest { StrolchRealm secondRealm = runtimeMock.getRealm("second"); assertEquals(DataStoreMode.TRANSACTIONAL, secondRealm.getMode()); Resource expectedRes2 = ModelGenerator.createResource(expectedId2, "Bla bla", type); - try (StrolchTransaction tx = secondRealm.openTx()) { + try (StrolchTransaction tx = secondRealm.openTx(certificate, "test")) { tx.getResourceMap().add(tx, expectedRes2); } - try (StrolchTransaction tx = secondRealm.openTx()) { + try (StrolchTransaction tx = secondRealm.openTx(certificate, "test")) { Resource res = tx.getResourceMap().getBy(tx, type, expectedId2); assertEquals("Should find object previously added in same realm!", expectedRes2, res); } @@ -104,7 +110,7 @@ public class RealmTest extends AbstractModelTest { { StrolchRealm secondRealm = runtimeMock.getRealm("second"); - try (StrolchTransaction tx = secondRealm.openTx()) { + try (StrolchTransaction tx = secondRealm.openTx(certificate, "test")) { Resource res = tx.getResourceMap().getBy(tx, type, expectedId1); assertNull("Should not find object added in differenct realm!", res); } diff --git a/src/test/resources/cachedruntime/config/PrivilegeConfig.xml b/src/test/resources/cachedruntime/config/PrivilegeConfig.xml new file mode 100644 index 000000000..9d7a227e3 --- /dev/null +++ b/src/test/resources/cachedruntime/config/PrivilegeConfig.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/cachedruntime/config/PrivilegeModel.xml b/src/test/resources/cachedruntime/config/PrivilegeModel.xml new file mode 100644 index 000000000..14af39def --- /dev/null +++ b/src/test/resources/cachedruntime/config/PrivilegeModel.xml @@ -0,0 +1,36 @@ + + + + + + SYSTEM + + agent + + + + Application + Administrator + ENABLED + en_GB + + PrivilegeAdmin + AppUser + + + + + + + + + true + + + + + true + + + + \ No newline at end of file diff --git a/src/test/resources/cachedruntime/config/StrolchConfiguration.xml b/src/test/resources/cachedruntime/config/StrolchConfiguration.xml index b030e7899..733a7bf4b 100644 --- a/src/test/resources/cachedruntime/config/StrolchConfiguration.xml +++ b/src/test/resources/cachedruntime/config/StrolchConfiguration.xml @@ -7,13 +7,23 @@ true + + PrivilegeHandler + li.strolch.runtime.privilege.PrivilegeHandler + li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler + + PrivilegeConfig.xml + + RealmHandler li.strolch.agent.api.RealmHandler li.strolch.agent.impl.DefaultRealmHandler + PrivilegeHandler PersistenceHandler TRANSACTIONAL + true diff --git a/src/test/resources/realmtest/config/PrivilegeConfig.xml b/src/test/resources/realmtest/config/PrivilegeConfig.xml new file mode 100644 index 000000000..9d7a227e3 --- /dev/null +++ b/src/test/resources/realmtest/config/PrivilegeConfig.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/realmtest/config/PrivilegeModel.xml b/src/test/resources/realmtest/config/PrivilegeModel.xml new file mode 100644 index 000000000..14af39def --- /dev/null +++ b/src/test/resources/realmtest/config/PrivilegeModel.xml @@ -0,0 +1,36 @@ + + + + + + SYSTEM + + agent + + + + Application + Administrator + ENABLED + en_GB + + PrivilegeAdmin + AppUser + + + + + + + + + true + + + + + true + + + + \ No newline at end of file diff --git a/src/test/resources/realmtest/config/StrolchConfiguration.xml b/src/test/resources/realmtest/config/StrolchConfiguration.xml index 6367afe64..d80df1c91 100644 --- a/src/test/resources/realmtest/config/StrolchConfiguration.xml +++ b/src/test/resources/realmtest/config/StrolchConfiguration.xml @@ -7,15 +7,26 @@ true + + PrivilegeHandler + li.strolch.runtime.privilege.PrivilegeHandler + li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler + + PrivilegeConfig.xml + + RealmHandler li.strolch.agent.api.RealmHandler li.strolch.agent.impl.DefaultRealmHandler + PrivilegeHandler PersistenceHandler first, second TRANSACTIONAL TRANSACTIONAL + true + true diff --git a/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml b/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml new file mode 100644 index 000000000..9d7a227e3 --- /dev/null +++ b/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/transactionalruntime/config/PrivilegeModel.xml b/src/test/resources/transactionalruntime/config/PrivilegeModel.xml new file mode 100644 index 000000000..14af39def --- /dev/null +++ b/src/test/resources/transactionalruntime/config/PrivilegeModel.xml @@ -0,0 +1,36 @@ + + + + + + SYSTEM + + agent + + + + Application + Administrator + ENABLED + en_GB + + PrivilegeAdmin + AppUser + + + + + + + + + true + + + + + true + + + + \ No newline at end of file diff --git a/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml b/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml index b030e7899..733a7bf4b 100644 --- a/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml +++ b/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml @@ -7,13 +7,23 @@ true + + PrivilegeHandler + li.strolch.runtime.privilege.PrivilegeHandler + li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler + + PrivilegeConfig.xml + + RealmHandler li.strolch.agent.api.RealmHandler li.strolch.agent.impl.DefaultRealmHandler + PrivilegeHandler PersistenceHandler TRANSACTIONAL + true From a7f7cae6414a9fe081fdaac0281d4cf17b21a710 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Sun, 24 Aug 2014 12:45:14 +0200 Subject: [PATCH 50/61] [Major] Moved the auditing trail to the ElementMaps themselves This means that we can't access the ElementMaps from the Realms, but must use the TX (this was better anyhow) --- .../persistence/postgresql/DaoCommand.java | 4 +- .../postgresql/PostgreSqlAuditDao.java | 56 +++++++++---------- .../persistence/postgresql/PostgresqlDao.java | 35 ++++++------ .../dao/test/ObserverUpdateTest.java | 14 ++--- .../postgresql/dao/test/RealmTest.java | 46 ++++++++------- 5 files changed, 80 insertions(+), 75 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/DaoCommand.java b/src/main/java/li/strolch/persistence/postgresql/DaoCommand.java index 403684380..a878f50c1 100644 --- a/src/main/java/li/strolch/persistence/postgresql/DaoCommand.java +++ b/src/main/java/li/strolch/persistence/postgresql/DaoCommand.java @@ -15,12 +15,12 @@ */ package li.strolch.persistence.postgresql; -import li.strolch.persistence.api.ModificationResult; +import li.strolch.persistence.api.TransactionResult; /** * @author Robert von Burg */ public interface DaoCommand { - public void doComand(ModificationResult modificationResult); + public void doComand(TransactionResult txResult); } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java index 8884eedae..c7874102c 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java @@ -50,7 +50,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public boolean hasElement(String type, Long id) { - String sql = "select count(*) from audits where element_type = ? and id = ?"; + String sql = "select count(*) from audits where element_type = ? and id = ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); @@ -64,18 +64,18 @@ public class PostgreSqlAuditDao implements AuditDao { if (numberOfElements == 1) return true; - String msg = MessageFormat.format("Non unique number of elements with type {0} and id {1}", type, id); + String msg = MessageFormat.format("Non unique number of elements with type {0} and id {1}", type, id); //$NON-NLS-1$ throw new StrolchPersistenceException(msg); } } catch (SQLException e) { - throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); + throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); //$NON-NLS-1$ } } @Override public long querySize(DateRange dateRange) { - String sql = "select count(*) from audits where date between ? and ?"; + String sql = "select count(*) from audits where date between ? and ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setDate(1, new Date(dateRange.getFromDate().getTime()), Calendar.getInstance()); @@ -87,13 +87,13 @@ public class PostgreSqlAuditDao implements AuditDao { } } catch (SQLException e) { - throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); + throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); //$NON-NLS-1$ } } @Override public long querySize(String type, DateRange dateRange) { - String sql = "select count(*) from audits where element_type = ? and date between ? and ?"; + String sql = "select count(*) from audits where element_type = ? and date between ? and ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); @@ -106,7 +106,7 @@ public class PostgreSqlAuditDao implements AuditDao { } } catch (SQLException e) { - throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); + throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); //$NON-NLS-1$ } } @@ -114,15 +114,15 @@ public class PostgreSqlAuditDao implements AuditDao { public Set queryTypes() { Set keySet = new HashSet<>(); - String sql = "select distinct element_type from audits"; + String sql = "select distinct element_type from audits"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { try (ResultSet result = statement.executeQuery()) { while (result.next()) { - keySet.add(result.getString("element_type")); + keySet.add(result.getString("element_type")); //$NON-NLS-1$ } } } catch (SQLException e) { - throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); //$NON-NLS-1$ } return keySet; @@ -131,7 +131,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public Audit queryBy(String type, Long id) { - String sql = "select id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type from audits where element_type = ? and id = ?"; + String sql = "select id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type from audits where element_type = ? and id = ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); @@ -143,18 +143,18 @@ public class PostgreSqlAuditDao implements AuditDao { } Audit audit = auditFrom(result); if (result.next()) - throw new StrolchPersistenceException("Non unique result for query: " + sql); + throw new StrolchPersistenceException("Non unique result for query: " + sql); //$NON-NLS-1$ return audit; } } catch (SQLException e) { - throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); //$NON-NLS-1$ } } @Override public List queryAll(String type, DateRange dateRange) { List list = new ArrayList<>(); - String sql = "select id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type from audits where element_type = ? and date between ? and ?"; + String sql = "select id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type from audits where element_type = ? and date between ? and ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); @@ -168,7 +168,7 @@ public class PostgreSqlAuditDao implements AuditDao { } } catch (SQLException e) { - throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); //$NON-NLS-1$ } return list; @@ -176,19 +176,19 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public void save(Audit audit) { - String sql = "insert into audits (id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?::access_type)"; - try (PreparedStatement preparedStatement = tx.getConnection().prepareStatement(sql)) { + String sql = "insert into audits (id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?::access_type)"; //$NON-NLS-1$ + try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { setAuditFields(audit, preparedStatement); int count = preparedStatement.executeUpdate(); if (count != 1) { throw new StrolchPersistenceException(MessageFormat.format( - "Expected to create 1 record, but created {0} for audit {2}", count, audit.getId())); + "Expected to create 1 record, but created {0} for audit {2}", count, audit.getId())); //$NON-NLS-1$ } } catch (SQLException e) { - throw new StrolchPersistenceException(MessageFormat.format("Failed to update Audit {0} due to {1}", audit, + throw new StrolchPersistenceException(MessageFormat.format("Failed to update Audit {0} due to {1}", audit, //$NON-NLS-1$ e.getLocalizedMessage()), e); } } @@ -202,8 +202,8 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public void update(Audit audit) { - String sql = "update audits set id = ?, username = ?, firstname = ?, lastname = ?, date = ?, element_type = ?, element_accessed = ?, new_version = ?, action = ?, access_type = ?::access_type where id = ?"; - try (PreparedStatement preparedStatement = tx.getConnection().prepareStatement(sql)) { + String sql = "update audits set id = ?, username = ?, firstname = ?, lastname = ?, date = ?, element_type = ?, element_accessed = ?, new_version = ?, action = ?, access_type = ?::access_type where id = ?"; //$NON-NLS-1$ + try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { setAuditFields(audit, preparedStatement); preparedStatement.setLong(11, audit.getId()); @@ -211,11 +211,11 @@ public class PostgreSqlAuditDao implements AuditDao { int count = preparedStatement.executeUpdate(); if (count != 1) { throw new StrolchPersistenceException(MessageFormat.format( - "Expected to update 1 record, but updated {0} for audit {2}", count, audit.getId())); + "Expected to update 1 record, but updated {0} for audit {2}", count, audit.getId())); //$NON-NLS-1$ } } catch (SQLException e) { - throw new StrolchPersistenceException(MessageFormat.format("Failed to update Audit {0} due to {1}", audit, + throw new StrolchPersistenceException(MessageFormat.format("Failed to update Audit {0} due to {1}", audit, //$NON-NLS-1$ e.getLocalizedMessage()), e); } } @@ -229,20 +229,20 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public void remove(Audit audit) { - String sql = "delete from audits where id = ?"; + String sql = "delete from audits where id = ?"; //$NON-NLS-1$ try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { preparedStatement.setLong(1, audit.getId()); int count = preparedStatement.executeUpdate(); if (count != 1) { - String msg = "Expected to delete 1 audit with id {0} but deleted {1} elements!"; + String msg = "Expected to delete 1 audit with id {0} but deleted {1} elements!"; //$NON-NLS-1$ msg = MessageFormat.format(msg, audit.getId(), count); throw new StrolchPersistenceException(msg); } } catch (SQLException e) { - throw new StrolchPersistenceException(MessageFormat.format("Failed to remove {0} due to {2}", + throw new StrolchPersistenceException(MessageFormat.format("Failed to remove {0} due to {2}", //$NON-NLS-1$ audit.getId(), e.getLocalizedMessage()), e); } } @@ -256,7 +256,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public long removeAll(String type, DateRange dateRange) { - String sql = "delete from audits where element_type = ? and date between ? and ?"; + String sql = "delete from audits where element_type = ? and date between ? and ?"; //$NON-NLS-1$ try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { preparedStatement.setString(1, type); @@ -267,7 +267,7 @@ public class PostgreSqlAuditDao implements AuditDao { return modCount; } catch (SQLException e) { - throw new StrolchPersistenceException(MessageFormat.format("Failed to remove all elements due to {0}", + throw new StrolchPersistenceException(MessageFormat.format("Failed to remove all elements due to {0}", //$NON-NLS-1$ e.getLocalizedMessage()), e); } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java index 163da325e..885847d4f 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java @@ -26,7 +26,6 @@ import java.util.List; import java.util.Set; import li.strolch.model.StrolchElement; -import li.strolch.persistence.api.ModificationResult; import li.strolch.persistence.api.StrolchDao; import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.TransactionResult; @@ -224,9 +223,9 @@ public abstract class PostgresqlDao implements Strolch public void save(final T res) { this.commands.add(new DaoCommand() { @Override - public void doComand(ModificationResult modificationResult) { + public void doComand(TransactionResult txResult) { internalSave(res); - modificationResult.getCreated().add(res); + txResult.incCreated(1); } }); } @@ -235,11 +234,11 @@ public abstract class PostgresqlDao implements Strolch public void saveAll(final List elements) { this.commands.add(new DaoCommand() { @Override - public void doComand(ModificationResult modificationResult) { + public void doComand(TransactionResult txResult) { for (T element : elements) { internalSave(element); } - modificationResult.getCreated().addAll(elements); + txResult.incCreated(elements.size()); } }); } @@ -248,9 +247,9 @@ public abstract class PostgresqlDao implements Strolch public void update(final T element) { this.commands.add(new DaoCommand() { @Override - public void doComand(ModificationResult modificationResult) { + public void doComand(TransactionResult txResult) { internalUpdate(element); - modificationResult.getUpdated().add(element); + txResult.incUpdated(1); } }); } @@ -259,11 +258,11 @@ public abstract class PostgresqlDao implements Strolch public void updateAll(final List elements) { this.commands.add(new DaoCommand() { @Override - public void doComand(ModificationResult modificationResult) { + public void doComand(TransactionResult txResult) { for (T element : elements) { internalUpdate(element); } - modificationResult.getUpdated().addAll(elements); + txResult.incUpdated(elements.size()); } }); } @@ -272,9 +271,9 @@ public abstract class PostgresqlDao implements Strolch public void remove(final T element) { this.commands.add(new DaoCommand() { @Override - public void doComand(ModificationResult modificationResult) { + public void doComand(TransactionResult txResult) { internalRemove(element); - modificationResult.getDeleted().add(element); + txResult.incDeleted(1); } }); } @@ -283,11 +282,11 @@ public abstract class PostgresqlDao implements Strolch public void removeAll(final List elements) { this.commands.add(new DaoCommand() { @Override - public void doComand(ModificationResult modificationResult) { + public void doComand(TransactionResult txResult) { for (T element : elements) { internalRemove(element); } - modificationResult.getDeleted().addAll(elements); + txResult.incDeleted(elements.size()); } }); } @@ -299,8 +298,9 @@ public abstract class PostgresqlDao implements Strolch this.commands.add(new DaoCommand() { @Override - public void doComand(ModificationResult modificationResult) { + public void doComand(TransactionResult txResult) { internalRemoveAll(toRemove); + txResult.incDeleted(toRemove); } }); @@ -314,8 +314,9 @@ public abstract class PostgresqlDao implements Strolch this.commands.add(new DaoCommand() { @Override - public void doComand(ModificationResult modificationResult) { + public void doComand(TransactionResult txResult) { internalRemoveAllBy(toRemove, type); + txResult.incDeleted(toRemove); } }); @@ -384,10 +385,8 @@ public abstract class PostgresqlDao implements Strolch } void commit(TransactionResult txResult) { - ModificationResult modificationResult = new ModificationResult(getClassName()); - txResult.addModificationResult(modificationResult); for (DaoCommand command : this.commands) { - command.doComand(modificationResult); + command.doComand(txResult); } } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index 9af319ff7..f47b6f8d9 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -33,7 +33,7 @@ import java.util.Map; import li.strolch.model.Order; import li.strolch.model.Resource; import li.strolch.model.State; -import li.strolch.model.StrolchElement; +import li.strolch.model.StrolchRootElement; import li.strolch.model.Tags; import li.strolch.persistence.api.ModificationResult; import li.strolch.persistence.api.StrolchTransaction; @@ -96,17 +96,17 @@ public class ObserverUpdateTest { } @Override - public void update(String key, List elements) { + public void update(String key, List elements) { getModificationResult(key).getUpdated().addAll(elements); } @Override - public void remove(String key, List elements) { + public void remove(String key, List elements) { getModificationResult(key).getDeleted().addAll(elements); } @Override - public void add(String key, List elements) { + public void add(String key, List elements) { getModificationResult(key).getCreated().addAll(elements); } } @@ -120,17 +120,17 @@ public class ObserverUpdateTest { runtimeMock.getContainer().getComponent(ObserverHandler.class).registerObserver(Tags.RESOURCE, observer); PrivilegeHandler privilegeHandler = runtimeMock.getAgent().getContainer().getPrivilegeHandler(); - Certificate certificate = privilegeHandler.authenticate("test", "test".getBytes()); + Certificate certificate = privilegeHandler.authenticate("test", "test".getBytes()); //$NON-NLS-1$ //$NON-NLS-2$ // create order Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType", new Date(), State.CREATED); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).openTx(certificate, "test")) { + try (StrolchTransaction tx = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).openTx(certificate, "test")) { //$NON-NLS-1$ tx.getOrderMap().add(tx, newOrder); } // create resource Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).openTx(certificate, "test");) { + try (StrolchTransaction tx = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).openTx(certificate, "test");) { //$NON-NLS-1$ tx.getResourceMap().add(tx, newResource); } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java index 78156edf9..d635ba916 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java @@ -40,6 +40,12 @@ import ch.eitchnet.privilege.model.Certificate; public class RealmTest extends AbstractModelTest { + private static final String TESTUSER2 = "testuser2"; //$NON-NLS-1$ + private static final String TESTUSER1 = "testuser1"; //$NON-NLS-1$ + private static final String SECOND = "second"; //$NON-NLS-1$ + private static final String TEST = "test"; //$NON-NLS-1$ + private static final String FIRST = "first"; //$NON-NLS-1$ + public static final String RUNTIME_PATH = "target/realmtest/"; //$NON-NLS-1$ public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ public static final String CONFIG_SRC = "src/test/resources/realmtest"; //$NON-NLS-1$ @@ -54,8 +60,8 @@ public class RealmTest extends AbstractModelTest { @BeforeClass public static void beforeClass() throws SQLException { - dropSchema("jdbc:postgresql://localhost/testdb1", "testuser1", "test"); - dropSchema("jdbc:postgresql://localhost/testdb2", "testuser2", "test"); + dropSchema("jdbc:postgresql://localhost/testdb1", TESTUSER1, TEST); //$NON-NLS-1$ + dropSchema("jdbc:postgresql://localhost/testdb2", TESTUSER2, TEST); //$NON-NLS-1$ File rootPath = new File(RUNTIME_PATH); File configSrc = new File(CONFIG_SRC); @@ -67,52 +73,52 @@ public class RealmTest extends AbstractModelTest { @Before public void before() { - this.realmName = "second"; + this.realmName = SECOND; } @Test public void testDifferentRealms() { - String expectedId1 = "@realmTestId1"; - String expectedId2 = "@realmTestId2"; - String type = "Bla"; + String expectedId1 = "@realmTestId1"; //$NON-NLS-1$ + String expectedId2 = "@realmTestId2"; //$NON-NLS-1$ + String type = "Bla"; //$NON-NLS-1$ PrivilegeHandler privilegeHandler = runtimeMock.getAgent().getContainer().getPrivilegeHandler(); - Certificate certificate = privilegeHandler.authenticate("test", "test".getBytes()); + Certificate certificate = privilegeHandler.authenticate(TEST, TEST.getBytes()); { - StrolchRealm firstRealm = runtimeMock.getRealm("first"); + StrolchRealm firstRealm = runtimeMock.getRealm(FIRST); assertEquals(DataStoreMode.TRANSACTIONAL, firstRealm.getMode()); - Resource expectedRes1 = ModelGenerator.createResource(expectedId1, "Bla bla", type); - try (StrolchTransaction tx = firstRealm.openTx(certificate, "test")) { + Resource expectedRes1 = ModelGenerator.createResource(expectedId1, "Bla bla", type); //$NON-NLS-1$ + try (StrolchTransaction tx = firstRealm.openTx(certificate, TEST)) { tx.getResourceMap().add(tx, expectedRes1); } - try (StrolchTransaction tx = firstRealm.openTx(certificate, "test")) { + try (StrolchTransaction tx = firstRealm.openTx(certificate, TEST)) { Resource res = tx.getResourceMap().getBy(tx, type, expectedId1); - assertEquals("Should find object previously added in same realm!", expectedRes1, res); + assertEquals("Should find object previously added in same realm!", expectedRes1, res); //$NON-NLS-1$ } } { - StrolchRealm secondRealm = runtimeMock.getRealm("second"); + StrolchRealm secondRealm = runtimeMock.getRealm(SECOND); assertEquals(DataStoreMode.TRANSACTIONAL, secondRealm.getMode()); - Resource expectedRes2 = ModelGenerator.createResource(expectedId2, "Bla bla", type); - try (StrolchTransaction tx = secondRealm.openTx(certificate, "test")) { + Resource expectedRes2 = ModelGenerator.createResource(expectedId2, "Bla bla", type); //$NON-NLS-1$ + try (StrolchTransaction tx = secondRealm.openTx(certificate, TEST)) { tx.getResourceMap().add(tx, expectedRes2); } - try (StrolchTransaction tx = secondRealm.openTx(certificate, "test")) { + try (StrolchTransaction tx = secondRealm.openTx(certificate, TEST)) { Resource res = tx.getResourceMap().getBy(tx, type, expectedId2); - assertEquals("Should find object previously added in same realm!", expectedRes2, res); + assertEquals("Should find object previously added in same realm!", expectedRes2, res); //$NON-NLS-1$ } } { - StrolchRealm secondRealm = runtimeMock.getRealm("second"); - try (StrolchTransaction tx = secondRealm.openTx(certificate, "test")) { + StrolchRealm secondRealm = runtimeMock.getRealm(SECOND); + try (StrolchTransaction tx = secondRealm.openTx(certificate, TEST)) { Resource res = tx.getResourceMap().getBy(tx, type, expectedId1); - assertNull("Should not find object added in differenct realm!", res); + assertNull("Should not find object added in differenct realm!", res); //$NON-NLS-1$ } } } From 353d39a0b12626f9d818c977ee782a77ac779c98 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Sun, 24 Aug 2014 17:23:48 +0200 Subject: [PATCH 51/61] [Project] set version to 1.0.0-SNAPSHOT --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index d9bba601c..558f377b0 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ li.strolch li.strolch.parent - 0.1.0-SNAPSHOT + 1.0.0-SNAPSHOT ../li.strolch.parent/pom.xml @@ -31,7 +31,7 @@ - + li.strolch li.strolch.model @@ -40,13 +40,13 @@ li.strolch li.strolch.agent - org.postgresql postgresql 9.3-1100-jdbc41 + li.strolch li.strolch.testbase From 0b67cc9802dfebe7c0cb58481fbeee4644ba1af1 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Sun, 24 Aug 2014 19:18:13 +0200 Subject: [PATCH 52/61] [Major] moved ObserverHandler to StrolchRealm - no component anymore Now the ObserverHandler is not a StrolchComponent anymore, and can be retrieved from the StrolchRealm. This makes the observer model be part of the realm, not global of the agent. --- .../postgresql/PostgreSqlPersistenceHandler.java | 7 +------ .../postgresql/dao/test/ObserverUpdateTest.java | 4 ++-- .../cachedruntime/config/StrolchConfiguration.xml | 5 ----- .../resources/realmtest/config/StrolchConfiguration.xml | 5 ----- .../transactionalruntime/config/StrolchConfiguration.xml | 5 ----- 5 files changed, 3 insertions(+), 23 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index 8e18e58f4..0b04337f1 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -39,7 +39,6 @@ import li.strolch.persistence.api.StrolchTransaction; import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.configuration.ComponentConfiguration; import li.strolch.runtime.configuration.StrolchConfigurationException; -import li.strolch.runtime.observer.ObserverHandler; import ch.eitchnet.privilege.model.Certificate; /** @@ -132,11 +131,7 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe @Override public StrolchTransaction openTx(StrolchRealm realm, Certificate certificate, String action) { - PostgreSqlStrolchTransaction tx = new PostgreSqlStrolchTransaction(realm, certificate, action, this); - if (getContainer().hasComponent(ObserverHandler.class)) { - tx.setObserverHandler(getContainer().getComponent(ObserverHandler.class)); - } - return tx; + return new PostgreSqlStrolchTransaction(realm, certificate, action, this); } Connection getConnection(String realm) { diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index f47b6f8d9..e999b280b 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -30,6 +30,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import li.strolch.agent.api.Observer; +import li.strolch.agent.api.ObserverHandler; import li.strolch.model.Order; import li.strolch.model.Resource; import li.strolch.model.State; @@ -38,8 +40,6 @@ import li.strolch.model.Tags; import li.strolch.persistence.api.ModificationResult; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.runtime.StrolchConstants; -import li.strolch.runtime.observer.Observer; -import li.strolch.runtime.observer.ObserverHandler; import li.strolch.runtime.privilege.PrivilegeHandler; import li.strolch.testbase.runtime.RuntimeMock; diff --git a/src/test/resources/cachedruntime/config/StrolchConfiguration.xml b/src/test/resources/cachedruntime/config/StrolchConfiguration.xml index 733a7bf4b..6f256379d 100644 --- a/src/test/resources/cachedruntime/config/StrolchConfiguration.xml +++ b/src/test/resources/cachedruntime/config/StrolchConfiguration.xml @@ -38,10 +38,5 @@ test - - ObserverHandler - li.strolch.runtime.observer.ObserverHandler - li.strolch.runtime.observer.DefaultObserverHandler - \ No newline at end of file diff --git a/src/test/resources/realmtest/config/StrolchConfiguration.xml b/src/test/resources/realmtest/config/StrolchConfiguration.xml index d80df1c91..e723d0aba 100644 --- a/src/test/resources/realmtest/config/StrolchConfiguration.xml +++ b/src/test/resources/realmtest/config/StrolchConfiguration.xml @@ -46,10 +46,5 @@ test - - ObserverHandler - li.strolch.runtime.observer.ObserverHandler - li.strolch.runtime.observer.DefaultObserverHandler - \ No newline at end of file diff --git a/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml b/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml index 733a7bf4b..6f256379d 100644 --- a/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml +++ b/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml @@ -38,10 +38,5 @@ test - - ObserverHandler - li.strolch.runtime.observer.ObserverHandler - li.strolch.runtime.observer.DefaultObserverHandler - \ No newline at end of file From 0e75f9b0d26b78ab8259c66a72d2b324764a3704 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Sun, 24 Aug 2014 19:29:43 +0200 Subject: [PATCH 53/61] [Minor] fixed broken tests due to wrong checking for observer updates --- .../postgresql/dao/test/ObserverUpdateTest.java | 11 ++++++----- .../cachedruntime/config/StrolchConfiguration.xml | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java index e999b280b..bb1279902 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java @@ -31,7 +31,7 @@ import java.util.List; import java.util.Map; import li.strolch.agent.api.Observer; -import li.strolch.agent.api.ObserverHandler; +import li.strolch.agent.api.StrolchRealm; import li.strolch.model.Order; import li.strolch.model.Resource; import li.strolch.model.State; @@ -116,21 +116,22 @@ public class ObserverUpdateTest { // register an observer for orders and resources ElementAddedObserver observer = new ElementAddedObserver(); - runtimeMock.getContainer().getComponent(ObserverHandler.class).registerObserver(Tags.ORDER, observer); - runtimeMock.getContainer().getComponent(ObserverHandler.class).registerObserver(Tags.RESOURCE, observer); + StrolchRealm realm = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM); + realm.getObserverHandler().registerObserver(Tags.ORDER, observer); + realm.getObserverHandler().registerObserver(Tags.RESOURCE, observer); PrivilegeHandler privilegeHandler = runtimeMock.getAgent().getContainer().getPrivilegeHandler(); Certificate certificate = privilegeHandler.authenticate("test", "test".getBytes()); //$NON-NLS-1$ //$NON-NLS-2$ // create order Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType", new Date(), State.CREATED); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).openTx(certificate, "test")) { //$NON-NLS-1$ + try (StrolchTransaction tx = realm.openTx(certificate, "test")) { //$NON-NLS-1$ tx.getOrderMap().add(tx, newOrder); } // create resource Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - try (StrolchTransaction tx = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).openTx(certificate, "test");) { //$NON-NLS-1$ + try (StrolchTransaction tx = realm.openTx(certificate, "test");) { //$NON-NLS-1$ tx.getResourceMap().add(tx, newResource); } diff --git a/src/test/resources/cachedruntime/config/StrolchConfiguration.xml b/src/test/resources/cachedruntime/config/StrolchConfiguration.xml index 6f256379d..fe782ba2d 100644 --- a/src/test/resources/cachedruntime/config/StrolchConfiguration.xml +++ b/src/test/resources/cachedruntime/config/StrolchConfiguration.xml @@ -24,6 +24,7 @@ TRANSACTIONAL true + true From 65402e9006b02958a3fcaee8c166e5d0fcc630e5 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 25 Aug 2014 22:53:16 +0200 Subject: [PATCH 54/61] [New] Implemented PostgreSQL querying --- .../postgresql/PostgreSqlOrderDao.java | 32 +- .../PostgreSqlOrderQueryVisitor.java | 56 ++++ .../postgresql/PostgreSqlQueryVisitor.java | 307 ++++++++++++++++++ .../postgresql/PostgreSqlResourceDao.java | 32 +- .../PostgreSqlResourceQueryVisitor.java | 40 +++ .../postgresql/dao/test/QueryTest.java | 223 +++++++++++++ 6 files changed, 684 insertions(+), 6 deletions(-) create mode 100644 src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java create mode 100644 src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java create mode 100644 src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java create mode 100644 src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java index 245c91da3..d5268098b 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java @@ -19,9 +19,11 @@ import java.io.IOException; import java.io.InputStream; import java.sql.Date; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLXML; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.Calendar; import java.util.List; @@ -46,6 +48,8 @@ import org.xml.sax.SAXException; @SuppressWarnings("nls") public class PostgreSqlOrderDao extends PostgresqlDao implements OrderDao { + public static final String ORDERS = "orders"; + /** * @param tx */ @@ -60,7 +64,7 @@ public class PostgreSqlOrderDao extends PostgresqlDao implements OrderDao @Override protected String getTableName() { - return "orders"; + return ORDERS; } @Override @@ -157,7 +161,29 @@ public class PostgreSqlOrderDao extends PostgresqlDao implements OrderDao @Override public List doQuery(OrderQuery query, OrderVisitor orderVisitor) { - // TODO Auto-generated method stub - return null; + + PostgreSqlOrderQueryVisitor queryVisitor = new PostgreSqlOrderQueryVisitor("id, asxml"); + query.accept(queryVisitor); + queryVisitor.validate(); + + List list = new ArrayList<>(); + + String sql = queryVisitor.getSql(); + try (PreparedStatement ps = PostgreSqlOrderDao.this.tx.getConnection().prepareStatement(sql)) { + queryVisitor.setValues(ps); + + try (ResultSet result = ps.executeQuery()) { + while (result.next()) { + String id = result.getString("id"); + SQLXML sqlxml = result.getSQLXML("asxml"); + Order t = parseFromXml(id, queryVisitor.getType(), sqlxml); + list.add(orderVisitor.visit(t)); + } + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to perform query due to: " + e.getMessage(), e); + } + + return list; } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java new file mode 100644 index 000000000..4ba9288cb --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java @@ -0,0 +1,56 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import li.strolch.model.Tags; +import li.strolch.model.query.DateSelection; +import li.strolch.model.query.OrderQueryVisitor; +import li.strolch.model.query.StateSelection; + +/** + * @author Robert von Burg + */ +public class PostgreSqlOrderQueryVisitor extends PostgreSqlQueryVisitor implements OrderQueryVisitor { + + /** + * @param fields + */ + public PostgreSqlOrderQueryVisitor(String fields) { + super(fields); + } + + protected String getClassName() { + return Tags.ORDER; + } + + protected String getTableName() { + return PostgreSqlOrderDao.ORDERS; + } + + @Override + public void visit(DateSelection selection) { + sb.append(indent); + sb.append("date = ?\n"); + values.add(selection.getDate()); + } + + @Override + public void visit(StateSelection selection) { + sb.append(indent); + sb.append("stae = ?\n"); + values.add(selection.getState().name()); + } +} diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java new file mode 100644 index 000000000..15fff09b6 --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java @@ -0,0 +1,307 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import li.strolch.model.query.AndSelection; +import li.strolch.model.query.IdSelection; +import li.strolch.model.query.NameSelection; +import li.strolch.model.query.NotSelection; +import li.strolch.model.query.OrSelection; +import li.strolch.model.query.ParameterSelection.BooleanParameterSelection; +import li.strolch.model.query.ParameterSelection.DateParameterSelection; +import li.strolch.model.query.ParameterSelection.DateRangeParameterSelection; +import li.strolch.model.query.ParameterSelection.FloatParameterSelection; +import li.strolch.model.query.ParameterSelection.IntegerParameterSelection; +import li.strolch.model.query.ParameterSelection.LongParameterSelection; +import li.strolch.model.query.ParameterSelection.StringListParameterSelection; +import li.strolch.model.query.ParameterSelection.StringParameterSelection; +import li.strolch.model.query.ParameterSelectionVisitor; +import li.strolch.model.query.Selection; +import li.strolch.model.query.StrolchElementSelectionVisitor; +import li.strolch.model.query.StrolchTypeNavigation; +import ch.eitchnet.utils.StringMatchMode; +import ch.eitchnet.utils.dbc.DBC; +import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; + +/** + * @author Robert von Burg + */ +public abstract class PostgreSqlQueryVisitor implements StrolchElementSelectionVisitor, ParameterSelectionVisitor { + + protected StringBuilder sql; + protected StringBuilder sb; + protected String type; + protected List values; + protected boolean any; + protected String indent; + private String sqlAsString; + + public PostgreSqlQueryVisitor(String fields) { + this.indent = ""; + this.sql = new StringBuilder(); + this.sb = new StringBuilder(); + this.values = new ArrayList<>(); + + this.sql.append("select "); + this.sql.append(fields); + this.sql.append("\nfrom\n"); + this.sql.append(" "); + this.sql.append(getTableName()); + this.indent = " "; + } + + public String getSql() { + if (sqlAsString != null) + return sqlAsString; + + this.sql.append("\nwhere\n"); + this.sql.append(this.indent); + + if (this.any) { + this.sql.append("type = ?"); + sqlAsString = this.sql.toString(); + return sqlAsString; + } + + this.sql.append("type = ? and\n"); + + this.sql.append(this.sb.toString()); + sqlAsString = this.sql.toString(); + return sqlAsString; + } + + /** + * @return the any + */ + public boolean isAny() { + return this.any; + } + + /** + * @return the values + */ + public List getValues() { + return this.values; + } + + public String getType() { + return this.type; + } + + public void validate() { + DBC.INTERIM.assertNotEmpty("No navigation was set!", this.type); + } + + protected abstract String getClassName(); + + protected abstract String getTableName(); + + @Override + public void visit(StrolchTypeNavigation navigation) { + this.type = navigation.getType(); + } + + @Override + public void visit(IdSelection selection) { + this.sb.append(this.indent); + List ids = selection.getIds(); + if (ids.isEmpty()) + return; + int size = ids.size(); + if (size == 1) { + this.sb.append("id = ?\n"); + this.values.add(ids.get(0)); + } else { + this.sb.append("id in ("); + Iterator iter = ids.iterator(); + while (iter.hasNext()) { + String id = iter.next(); + this.sb.append("?"); + this.values.add(id); + if (iter.hasNext()) + this.sb.append(", "); + } + this.sb.append(" )\n"); + } + } + + @Override + public void visit(NameSelection selection) { + this.sb.append(this.indent); + String name = selection.getName(); + + // CS EQ + // 1. x x + // 2. x o + // 3. o x + // 4. o o + + StringMatchMode mm = selection.getMatchMode(); + if (mm.isCaseSensitve() && mm.isEquals()) { + this.sb.append("name = ?\n"); + this.values.add(name); + } else if (!mm.isCaseSensitve() && mm.isEquals()) { + this.sb.append("lower(name) = lower(?)\n"); + this.values.add(name); + } else if (!mm.isEquals() && mm.isCaseSensitve()) { + this.sb.append("name like ?"); + this.values.add("%" + name + "%"); + } else { + this.sb.append("lower(name) like ?"); + this.values.add(name.toLowerCase()); + } + } + + @Override + public void visitAny() { + this.any = true; + } + + @Override + public void visitAnd(AndSelection andSelection) { + this.sb.append(this.indent); + List selections = andSelection.getSelections(); + this.sb.append("( \n"); + Iterator iter = selections.iterator(); + String indent = this.indent; + this.indent += " "; + while (iter.hasNext()) { + Selection selection = iter.next(); + selection.accept(this); + if (iter.hasNext()) { + this.sb.append(indent); + this.sb.append("and\n"); + } + } + this.indent = indent; + this.sb.append(this.indent); + this.sb.append(")\n"); + } + + @Override + public void visitOr(OrSelection orSelection) { + this.sb.append(this.indent); + List selections = orSelection.getSelections(); + this.sb.append("( \n"); + Iterator iter = selections.iterator(); + String indent = this.indent; + this.indent += " "; + while (iter.hasNext()) { + Selection selection = iter.next(); + selection.accept(this); + if (iter.hasNext()) { + this.sb.append(indent); + this.sb.append("or\n"); + } + } + this.indent = indent; + this.sb.append(this.indent); + this.sb.append(")\n"); + } + + @Override + public void visitNot(NotSelection notSelection) { + this.sb.append(this.indent); + List selections = notSelection.getSelections(); + this.sb.append("not ( \n"); + Iterator iter = selections.iterator(); + String indent = this.indent; + this.indent += " "; + while (iter.hasNext()) { + Selection selection = iter.next(); + selection.accept(this); + if (iter.hasNext()) { + this.sb.append(indent); + this.sb.append("and\n"); + } + } + this.indent = indent; + this.sb.append(this.indent); + this.sb.append(")\n"); + } + + private void xpath(String bagKey, String paramKey, String paramValue) { + this.sb.append(this.indent); + String xpath = "cast(xpath('//Resource/ParameterBag[@Id=\"${bagKey}\"]/Parameter[@Id=\"${paramKey}\" and @Value=\"${paramValue}\"]', asxml) as text[]) != '{}'\n"; + xpath = xpath.replace("${bagKey}", bagKey); + xpath = xpath.replace("${paramKey}", paramKey); + xpath = xpath.replace("${paramValue}", paramValue); + this.sb.append(xpath); + } + + @Override + public void visit(StringParameterSelection selection) { + xpath(selection.getBagKey(), selection.getParamKey(), selection.getValue()); + } + + @Override + public void visit(IntegerParameterSelection selection) { + xpath(selection.getBagKey(), selection.getParamKey(), selection.getValue().toString()); + } + + @Override + public void visit(BooleanParameterSelection selection) { + xpath(selection.getBagKey(), selection.getParamKey(), selection.getValue().toString()); + } + + @Override + public void visit(LongParameterSelection selection) { + xpath(selection.getBagKey(), selection.getParamKey(), selection.getValue().toString()); + } + + @Override + public void visit(FloatParameterSelection selection) { + xpath(selection.getBagKey(), selection.getParamKey(), selection.getValue().toString()); + } + + @Override + public void visit(DateParameterSelection selection) { + xpath(selection.getBagKey(), selection.getParamKey(), + ISO8601FormatFactory.getInstance().formatDate(selection.getValue())); + } + + @Override + public void visit(DateRangeParameterSelection selection) { + throw new UnsupportedOperationException("Not yet supported!"); + } + + @Override + public void visit(StringListParameterSelection selection) { + throw new UnsupportedOperationException("Not yet supported!"); + } + + /** + * @param ps + * @throws SQLException + */ + public void setValues(PreparedStatement ps) throws SQLException { + if (this.any) { + ps.setString(1, this.type); + return; + } + + ps.setString(1, this.type); + for (int i = 0; i < this.values.size(); i++) { + ps.setObject(i + 2, this.values.get(i)); + } + } +} diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java index d0455a956..4545b8a88 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java @@ -18,9 +18,11 @@ package li.strolch.persistence.postgresql; import java.io.IOException; import java.io.InputStream; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLXML; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.List; import javax.xml.parsers.ParserConfigurationException; @@ -44,6 +46,8 @@ import org.xml.sax.SAXException; @SuppressWarnings("nls") public class PostgreSqlResourceDao extends PostgresqlDao implements ResourceDao { + public static final String RESOURCES = "resources"; + protected PostgreSqlResourceDao(PostgreSqlStrolchTransaction tx) { super(tx); } @@ -55,7 +59,7 @@ public class PostgreSqlResourceDao extends PostgresqlDao implements Re @Override protected String getTableName() { - return "resources"; + return RESOURCES; } @Override @@ -146,7 +150,29 @@ public class PostgreSqlResourceDao extends PostgresqlDao implements Re @Override public List doQuery(ResourceQuery query, ResourceVisitor resourceVisitor) { - // TODO Auto-generated method stub - return null; + + PostgreSqlResourceQueryVisitor queryVisitor = new PostgreSqlResourceQueryVisitor("id, asxml"); + query.accept(queryVisitor); + queryVisitor.validate(); + + List list = new ArrayList<>(); + + String sql = queryVisitor.getSql(); + try (PreparedStatement ps = PostgreSqlResourceDao.this.tx.getConnection().prepareStatement(sql)) { + queryVisitor.setValues(ps); + + try (ResultSet result = ps.executeQuery()) { + while (result.next()) { + String id = result.getString("id"); + SQLXML sqlxml = result.getSQLXML("asxml"); + Resource t = parseFromXml(id, queryVisitor.getType(), sqlxml); + list.add(resourceVisitor.visit(t)); + } + } + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to perform query due to: " + e.getMessage(), e); + } + + return list; } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java new file mode 100644 index 000000000..349641144 --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java @@ -0,0 +1,40 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import li.strolch.model.Tags; +import li.strolch.model.query.ResourceQueryVisitor; + +/** + * @author Robert von Burg + */ +public class PostgreSqlResourceQueryVisitor extends PostgreSqlQueryVisitor implements ResourceQueryVisitor { + + /** + * @param fields + */ + public PostgreSqlResourceQueryVisitor(String fields) { + super(fields); + } + + protected String getClassName() { + return Tags.RESOURCE; + } + + protected String getTableName() { + return PostgreSqlResourceDao.RESOURCES; + } +} diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java new file mode 100644 index 000000000..aef53c158 --- /dev/null +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java @@ -0,0 +1,223 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql.dao.test; + +import static org.junit.Assert.assertEquals; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import li.strolch.model.query.IdSelection; +import li.strolch.model.query.NameSelection; +import li.strolch.model.query.OrSelection; +import li.strolch.model.query.OrderQuery; +import li.strolch.model.query.ParameterSelection; +import li.strolch.model.query.ResourceQuery; +import li.strolch.model.query.StrolchTypeNavigation; +import li.strolch.persistence.postgresql.PostgreSqlOrderQueryVisitor; +import li.strolch.persistence.postgresql.PostgreSqlQueryVisitor; +import li.strolch.persistence.postgresql.PostgreSqlResourceQueryVisitor; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ch.eitchnet.utils.StringMatchMode; + +/** + * @author Robert von Burg + */ +public class QueryTest { + + private static final Logger logger = LoggerFactory.getLogger(QueryTest.class); + + public Connection openConn() throws SQLException { + String url = "jdbc:postgresql://localhost/testdb"; + String username = "testuser"; + String password = "test"; + Connection connection = DriverManager.getConnection(url, username, password); + connection.setAutoCommit(false); + return connection; + } + + @Test + public void shouldQueryOrderAll() throws SQLException { + + OrderQuery query = new OrderQuery(new StrolchTypeNavigation("QTestType1")); + query.withAny(); + performOrderQuery(query, Arrays.asList("myTestOrder1")); + } + + @Test + public void shouldQueryResourceAll() throws SQLException { + + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.withAny(); + performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004")); + } + + @Test + public void shouldQueryOrder1() throws SQLException { + + OrderQuery query = new OrderQuery(new StrolchTypeNavigation("QTestType1")); + query.and().with(new IdSelection("myTestOrder1", "@2"), + new NameSelection("Test Name", StringMatchMode.EQUALS_CASE_SENSITIVE)); + performOrderQuery(query, Arrays.asList("myTestOrder1")); + } + + @Test + public void shouldQueryOrder2() throws SQLException { + + OrderQuery query = new OrderQuery(new StrolchTypeNavigation("QTestType1")); + query.or().with(new IdSelection("myTestOrder1", "@2"), + new NameSelection("Test Name", StringMatchMode.EQUALS_CASE_SENSITIVE)); + performOrderQuery(query, Arrays.asList("myTestOrder1")); + } + + @Test + public void shouldQueryResource1() throws SQLException { + + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.or().with(new IdSelection("@_00000000", "@_00000001"), + new NameSelection("Test Name", StringMatchMode.EQUALS_CASE_SENSITIVE)); + performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001")); + } + + @Test + public void shouldQueryResource2() throws SQLException { + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with( + new OrSelection(new IdSelection("@_00000000"), new IdSelection("@_00000001")), + new OrSelection(new NameSelection("My Resource 0", StringMatchMode.EQUALS_CASE_SENSITIVE), + new NameSelection("My Resource 1", StringMatchMode.EQUALS_CASE_SENSITIVE))); + performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001")); + } + + @Test + public void shouldQueryResourceByBooleParam() throws SQLException { + + // select id, name, type, asxml + // from + // resources + // where + // type = 'MyType1' and + // ( + // cast(xpath('//Resource/ParameterBag/Parameter[@Id="@param1" and @Value="true"]', asxml) as text[]) != '{}' + // ) + + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(ParameterSelection.booleanSelection("@bag01", "@param1", true)); + performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004")); + } + + @Test + public void shouldQueryResourceByFloagParam() throws SQLException { + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(ParameterSelection.floatSelection("@bag01", "@param2", 44.3)); + performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004")); + } + + @Test + public void shouldQueryResourceByIntegerParam() throws SQLException { + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(ParameterSelection.integerSelection("@bag01", "@param3", 77)); + performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004")); + } + + @Test + public void shouldQueryResourceByLongParam() throws SQLException { + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(ParameterSelection.longSelection("@bag01", "@param4", 4453234566L)); + performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004")); + } + + @Test + public void shouldQueryResourceByStringParam() throws SQLException { + + List expected = Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004"); + + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with( + ParameterSelection.stringSelection("@bag01", "@param5", "Strolch", + StringMatchMode.EQUALS_CASE_SENSITIVE)); + performResourceQuery(query, expected); + + query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with( + ParameterSelection.stringSelection("@bag01", "@param5", "strolch", + StringMatchMode.EQUALS_CASE_SENSITIVE)); + performResourceQuery(query, Arrays. asList()); + + query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with( + ParameterSelection.stringSelection("@bag01", "@param5", "strolch", + StringMatchMode.EQUALS_CASE_INSENSITIVE)); + performResourceQuery(query, expected); + + query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with( + ParameterSelection.stringSelection("@bag01", "@param5", "olch", + StringMatchMode.CONTAINS_CASE_INSENSITIVE)); + performResourceQuery(query, expected); + } + + @Test + public void shouldQueryResourceByDateParam() throws SQLException { + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(ParameterSelection.dateSelection("@bag01", "@param6", new Date(1354295525628L))); + performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004")); + + } + + private void performOrderQuery(OrderQuery query, List expected) throws SQLException { + PostgreSqlOrderQueryVisitor visitor = new PostgreSqlOrderQueryVisitor("id"); + query.accept(visitor); + List ids = queryIds(visitor); + assertEquals(expected, ids); + } + + private void performResourceQuery(ResourceQuery query, List expected) throws SQLException { + PostgreSqlResourceQueryVisitor visitor = new PostgreSqlResourceQueryVisitor("id"); + query.accept(visitor); + List ids = queryIds(visitor); + assertEquals(expected, ids); + } + + private List queryIds(PostgreSqlQueryVisitor visitor) throws SQLException { + String sql = visitor.getSql(); + logger.info("\n" + sql); + List ids = new ArrayList<>(); + try (Connection con = openConn()) { + try (PreparedStatement ps = con.prepareStatement(sql)) { + visitor.setValues(ps); + + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + ids.add(rs.getString(1)); + } + } + } + + return ids; + } +} From c7ad5d21c24ba3268b5c4ab2e2b4d33fcd0657b3 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 26 Aug 2014 22:02:49 +0200 Subject: [PATCH 55/61] [New] Implemented querying of StringParameter --- .../postgresql/PostgreSqlAuditDao.java | 27 ++- .../postgresql/PostgreSqlHelper.java | 138 +++++++++++++ .../PostgreSqlOrderQueryVisitor.java | 30 ++- .../postgresql/PostgreSqlQueryVisitor.java | 77 ++++--- .../postgresql/dao/test/QueryTest.java | 192 +++++++++++++++--- 5 files changed, 393 insertions(+), 71 deletions(-) create mode 100644 src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java index c7874102c..95120e07e 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java @@ -39,6 +39,9 @@ import ch.eitchnet.utils.collections.DateRange; */ public class PostgreSqlAuditDao implements AuditDao { + public static final String FIELDS = "id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type"; + public static final String TABLE_NAME = "audits"; + private PostgreSqlStrolchTransaction tx; /** @@ -50,7 +53,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public boolean hasElement(String type, Long id) { - String sql = "select count(*) from audits where element_type = ? and id = ?"; //$NON-NLS-1$ + String sql = "select count(*) from " + TABLE_NAME + " where element_type = ? and id = ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); @@ -75,7 +78,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public long querySize(DateRange dateRange) { - String sql = "select count(*) from audits where date between ? and ?"; //$NON-NLS-1$ + String sql = "select count(*) from " + TABLE_NAME + " where date between ? and ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setDate(1, new Date(dateRange.getFromDate().getTime()), Calendar.getInstance()); @@ -93,7 +96,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public long querySize(String type, DateRange dateRange) { - String sql = "select count(*) from audits where element_type = ? and date between ? and ?"; //$NON-NLS-1$ + String sql = "select count(*) from " + TABLE_NAME + " where element_type = ? and date between ? and ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); @@ -114,7 +117,7 @@ public class PostgreSqlAuditDao implements AuditDao { public Set queryTypes() { Set keySet = new HashSet<>(); - String sql = "select distinct element_type from audits"; //$NON-NLS-1$ + String sql = "select distinct element_type from " + TABLE_NAME; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { try (ResultSet result = statement.executeQuery()) { while (result.next()) { @@ -131,7 +134,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public Audit queryBy(String type, Long id) { - String sql = "select id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type from audits where element_type = ? and id = ?"; //$NON-NLS-1$ + String sql = "select " + FIELDS + " from " + TABLE_NAME + " where element_type = ? and id = ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); @@ -154,7 +157,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public List queryAll(String type, DateRange dateRange) { List list = new ArrayList<>(); - String sql = "select id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type from audits where element_type = ? and date between ? and ?"; //$NON-NLS-1$ + String sql = "select " + FIELDS + " from " + TABLE_NAME + " where element_type = ? and date between ? and ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); @@ -176,7 +179,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public void save(Audit audit) { - String sql = "insert into audits (id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?::access_type)"; //$NON-NLS-1$ + String sql = "insert into " + TABLE_NAME + " (" + FIELDS + ") values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?::access_type)"; //$NON-NLS-1$ try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { setAuditFields(audit, preparedStatement); @@ -202,7 +205,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public void update(Audit audit) { - String sql = "update audits set id = ?, username = ?, firstname = ?, lastname = ?, date = ?, element_type = ?, element_accessed = ?, new_version = ?, action = ?, access_type = ?::access_type where id = ?"; //$NON-NLS-1$ + String sql = "update " + TABLE_NAME + " set id = ?, username = ?, firstname = ?, lastname = ?, date = ?, element_type = ?, element_accessed = ?, new_version = ?, action = ?, access_type = ?::access_type where id = ?"; //$NON-NLS-1$ try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { setAuditFields(audit, preparedStatement); @@ -229,7 +232,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public void remove(Audit audit) { - String sql = "delete from audits where id = ?"; //$NON-NLS-1$ + String sql = "delete from " + TABLE_NAME + " where id = ?"; //$NON-NLS-1$ try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { preparedStatement.setLong(1, audit.getId()); @@ -256,7 +259,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public long removeAll(String type, DateRange dateRange) { - String sql = "delete from audits where element_type = ? and date between ? and ?"; //$NON-NLS-1$ + String sql = "delete from " + TABLE_NAME + " where element_type = ? and date between ? and ?"; //$NON-NLS-1$ try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { preparedStatement.setString(1, type); @@ -274,7 +277,9 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public List doQuery(AuditQuery query, AuditVisitor auditVisitor) { - // TODO Auto-generated method stub + + PostgreSqlAuditQueryVisitor queryVisitor = new PostgreSqlAuditQueryVisitor(FIELDS); + query.accept(queryVisitor); return null; } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java new file mode 100644 index 000000000..9bcec7a27 --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java @@ -0,0 +1,138 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import java.util.ArrayList; +import java.util.List; + +import ch.eitchnet.utils.StringMatchMode; + +/** + * @author Robert von Burg + */ +public class PostgreSqlHelper { + + public static String toSql(String indent, StringMatchMode mm, List values, String... query) { + + // CS EQ + // 1. x x + // 2. x o + // 3. o x + // 4. o o + + StringBuilder sb = new StringBuilder(); + if (mm.isCaseSensitve() && mm.isEquals()) { + if (query.length == 1) { + sb.append("name = ?\n"); + values.add(query[0]); + } else { + sb.append("name in ( "); + for (int i = 0; i < query.length; i++) { + sb.append("?"); + values.add(query[i]); + if (i < query.length - 1) + sb.append(", "); + } + sb.append(" )\n"); + } + } else if (!mm.isCaseSensitve() && mm.isEquals()) { + if (query.length == 1) { + sb.append("lower(name) = ?\n"); + values.add(query[0].toLowerCase()); + } else { + sb.append("lower(name) in ( "); + for (int i = 0; i < query.length; i++) { + sb.append("?"); + values.add(query[i].toLowerCase()); + if (i < query.length - 1) + sb.append(", "); + } + sb.append(" )\n"); + } + } else if (!mm.isEquals() && mm.isCaseSensitve()) { + if (query.length == 1) { + sb.append("name like ?\n"); + values.add("%" + query[0] + "%"); + } else { + sb.append("(\n"); + for (int i = 0; i < query.length; i++) { + sb.append(indent); + sb.append(" "); + sb.append("name like ?"); + values.add("%" + query[i] + "%"); + if (i < query.length - 1) + sb.append(" or"); + sb.append("\n"); + } + sb.append(")\n"); + } + } else { + if (query.length == 1) { + sb.append("lower(name) like ?\n"); + values.add("%" + query[0].toLowerCase() + "%"); + } else { + sb.append("(\n"); + for (int i = 0; i < query.length; i++) { + sb.append(indent); + sb.append(" "); + sb.append("lower(name) like ?"); + values.add("%" + query[i].toLowerCase() + "%"); + if (i < query.length - 1) + sb.append(" or"); + sb.append("\n"); + } + sb.append(")\n"); + } + } + + return sb.toString(); + } + + public static void main(String[] args) { + ArrayList values = new ArrayList<>(); + String sql = toSql(" ", StringMatchMode.CONTAINS_CASE_INSENSITIVE, values, "foo", "bar", "fub"); + System.out.println(sql); + System.out.println(); + + sql = toSql(" ", StringMatchMode.CONTAINS_CASE_INSENSITIVE, values, "foo"); + System.out.println(sql); + System.out.println(); + + sql = toSql(" ", StringMatchMode.CONTAINS_CASE_SENSITIVE, values, "foo", "bar", "fub"); + System.out.println(sql); + System.out.println(); + + sql = toSql(" ", StringMatchMode.CONTAINS_CASE_SENSITIVE, values, "foo"); + System.out.println(sql); + System.out.println(); + + sql = toSql(" ", StringMatchMode.EQUALS_CASE_INSENSITIVE, values, "foo", "bar", "fub"); + System.out.println(sql); + System.out.println(); + + sql = toSql(" ", StringMatchMode.EQUALS_CASE_INSENSITIVE, values, "foo"); + System.out.println(sql); + System.out.println(); + + sql = toSql(" ", StringMatchMode.EQUALS_CASE_SENSITIVE, values, "foo", "bar", "fub"); + System.out.println(sql); + System.out.println(); + + sql = toSql(" ", StringMatchMode.EQUALS_CASE_SENSITIVE, values, "foo"); + System.out.println(sql); + System.out.println(); + } +} diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java index 4ba9288cb..ec8f728f0 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java @@ -15,10 +15,13 @@ */ package li.strolch.persistence.postgresql; +import java.sql.Date; + import li.strolch.model.Tags; import li.strolch.model.query.DateSelection; import li.strolch.model.query.OrderQueryVisitor; import li.strolch.model.query.StateSelection; +import ch.eitchnet.utils.collections.DateRange; /** * @author Robert von Burg @@ -42,15 +45,34 @@ public class PostgreSqlOrderQueryVisitor extends PostgreSqlQueryVisitor implemen @Override public void visit(DateSelection selection) { - sb.append(indent); - sb.append("date = ?\n"); - values.add(selection.getDate()); + + // TODO handle inclusive and exclusive date ranges + + DateRange dateRange = selection.getDateRange(); + if (dateRange.isDate()) { + sb.append(indent); + sb.append("date = ?\n"); + values.add(new Date(dateRange.getFromDate().getTime())); + } else if (dateRange.isBounded()) { + sb.append(indent); + sb.append("date between ? and ?\n"); + values.add(new Date(dateRange.getFromDate().getTime())); + values.add(new Date(dateRange.getToDate().getTime())); + } else if (dateRange.isToBounded()) { + sb.append(indent); + sb.append("date < ?\n"); + values.add(new Date(dateRange.getToDate().getTime())); + } else if (dateRange.isFromBounded()) { + sb.append(indent); + sb.append("date > ?\n"); + values.add(new Date(dateRange.getFromDate().getTime())); + } } @Override public void visit(StateSelection selection) { sb.append(indent); - sb.append("stae = ?\n"); + sb.append("state = ?::order_state\n"); values.add(selection.getState().name()); } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java index 15fff09b6..f5d1e015e 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java @@ -15,6 +15,8 @@ */ package li.strolch.persistence.postgresql; +import static li.strolch.persistence.postgresql.PostgreSqlHelper.toSql; + import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; @@ -96,13 +98,6 @@ public abstract class PostgreSqlQueryVisitor implements StrolchElementSelectionV return this.any; } - /** - * @return the values - */ - public List getValues() { - return this.values; - } - public String getType() { return this.type; } @@ -148,27 +143,8 @@ public abstract class PostgreSqlQueryVisitor implements StrolchElementSelectionV public void visit(NameSelection selection) { this.sb.append(this.indent); String name = selection.getName(); - - // CS EQ - // 1. x x - // 2. x o - // 3. o x - // 4. o o - StringMatchMode mm = selection.getMatchMode(); - if (mm.isCaseSensitve() && mm.isEquals()) { - this.sb.append("name = ?\n"); - this.values.add(name); - } else if (!mm.isCaseSensitve() && mm.isEquals()) { - this.sb.append("lower(name) = lower(?)\n"); - this.values.add(name); - } else if (!mm.isEquals() && mm.isCaseSensitve()) { - this.sb.append("name like ?"); - this.values.add("%" + name + "%"); - } else { - this.sb.append("lower(name) like ?"); - this.values.add(name.toLowerCase()); - } + this.sb.append(toSql(this.indent, mm, this.values, name)); } @Override @@ -240,8 +216,8 @@ public abstract class PostgreSqlQueryVisitor implements StrolchElementSelectionV } private void xpath(String bagKey, String paramKey, String paramValue) { - this.sb.append(this.indent); String xpath = "cast(xpath('//Resource/ParameterBag[@Id=\"${bagKey}\"]/Parameter[@Id=\"${paramKey}\" and @Value=\"${paramValue}\"]', asxml) as text[]) != '{}'\n"; + this.sb.append(this.indent); xpath = xpath.replace("${bagKey}", bagKey); xpath = xpath.replace("${paramKey}", paramKey); xpath = xpath.replace("${paramValue}", paramValue); @@ -250,7 +226,50 @@ public abstract class PostgreSqlQueryVisitor implements StrolchElementSelectionV @Override public void visit(StringParameterSelection selection) { - xpath(selection.getBagKey(), selection.getParamKey(), selection.getValue()); + String value = selection.getValue(); + + String xpath = "xpath('//Resource/ParameterBag[@Id=\"${bagKey}\"]/Parameter[@Id=\"${paramKey}\"]/@Value', asxml))::TEXT AS content"; + xpath = xpath.replace("${bagKey}", selection.getBagKey()); + xpath = xpath.replace("${paramKey}", selection.getParamKey()); + + sb.append(this.indent); + sb.append("id in (\n"); + sb.append(this.indent); + sb.append(" SELECT id\n"); + sb.append(this.indent); + sb.append(" FROM (\n"); + sb.append(this.indent); + sb.append(" SELECT id, UNNEST("); + sb.append(xpath); + sb.append("\n"); + sb.append(this.indent); + sb.append("from "); + sb.append(getTableName()); + sb.append("\n"); + sb.append(this.indent); + sb.append(") AS alias\n"); + sb.append(this.indent); + sb.append("WHERE "); + + if (selection.getMatchMode().isEquals()) { + if (selection.getMatchMode().isCaseSensitve()) { + sb.append("content = ?\n"); + } else { + sb.append("content ILIKE ?\n"); + } + } else { + value = "%" + value + "%"; + if (selection.getMatchMode().isCaseSensitve()) { + sb.append("content LIKE ?\n"); + } else { + sb.append("content ILIKE ?\n"); + } + } + + sb.append(this.indent); + sb.append(")\n"); + + this.values.add(value); } @Override diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java index aef53c158..596990f7c 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java @@ -15,8 +15,16 @@ */ package li.strolch.persistence.postgresql.dao.test; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.CONFIG_SRC; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_PASSWORD; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_STORE_PATH_DIR; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_URL; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_USERNAME; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.RUNTIME_PATH; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.dropSchema; import static org.junit.Assert.assertEquals; +import java.io.File; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; @@ -24,24 +32,39 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.Date; +import java.util.HashSet; import java.util.List; +import li.strolch.agent.api.OrderMap; +import li.strolch.agent.api.ResourceMap; +import li.strolch.agent.api.StrolchRealm; +import li.strolch.model.ModelGenerator; +import li.strolch.model.State; +import li.strolch.model.query.DateSelection; import li.strolch.model.query.IdSelection; import li.strolch.model.query.NameSelection; import li.strolch.model.query.OrSelection; import li.strolch.model.query.OrderQuery; import li.strolch.model.query.ParameterSelection; import li.strolch.model.query.ResourceQuery; +import li.strolch.model.query.StateSelection; import li.strolch.model.query.StrolchTypeNavigation; +import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.postgresql.PostgreSqlOrderQueryVisitor; import li.strolch.persistence.postgresql.PostgreSqlQueryVisitor; import li.strolch.persistence.postgresql.PostgreSqlResourceQueryVisitor; +import li.strolch.runtime.StrolchConstants; +import li.strolch.testbase.runtime.RuntimeMock; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ch.eitchnet.privilege.model.Certificate; import ch.eitchnet.utils.StringMatchMode; /** @@ -50,6 +73,65 @@ import ch.eitchnet.utils.StringMatchMode; public class QueryTest { private static final Logger logger = LoggerFactory.getLogger(QueryTest.class); + private static RuntimeMock runtimeMock; + + private static Date past; + private static Date earlier; + private static Date current; + private static Date later; + private static Date future; + + @BeforeClass + public static void beforeClass() throws SQLException { + + dropSchema(DB_URL, DB_USERNAME, DB_PASSWORD); + + File rootPath = new File(RUNTIME_PATH); + File configSrc = new File(CONFIG_SRC); + runtimeMock = new RuntimeMock(); + runtimeMock.mockRuntime(rootPath, configSrc); + new File(rootPath, DB_STORE_PATH_DIR).mkdir(); + runtimeMock.startContainer(); + + Calendar cal = Calendar.getInstance(); + cal.clear(); + cal.set(2000, 1, 1); + past = cal.getTime(); + cal.set(2000, 4, 1); + earlier = cal.getTime(); + cal.set(2000, 6, 1); + current = cal.getTime(); + cal.set(2000, 8, 1); + later = cal.getTime(); + cal.set(2000, 11, 1); + future = cal.getTime(); + + Certificate cert = runtimeMock.getPrivilegeHandler().authenticate("test", "test".getBytes()); + StrolchRealm realm = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM); + try (StrolchTransaction tx = realm.openTx(cert, "test")) { + OrderMap orderMap = tx.getOrderMap(); + + orderMap.add(tx, ModelGenerator.createOrder("@1", "Order 1", "MyType1", earlier, State.CREATED)); + orderMap.add(tx, ModelGenerator.createOrder("@2", "Order 2", "MyType1", current, State.OPEN)); + orderMap.add(tx, ModelGenerator.createOrder("@3", "Order 3", "MyType1", later, State.CLOSED)); + orderMap.add(tx, ModelGenerator.createOrder("@4", "Order 4", "MyType2", earlier, State.CREATED)); + orderMap.add(tx, ModelGenerator.createOrder("@5", "Order 5", "MyType2", current, State.OPEN)); + orderMap.add(tx, ModelGenerator.createOrder("@6", "Order 6", "MyType2", later, State.CLOSED)); + + ResourceMap resourceMap = tx.getResourceMap(); + resourceMap.add(tx, ModelGenerator.createResource("@1", "Resource 1", "MyType1")); + resourceMap.add(tx, ModelGenerator.createResource("@2", "Resource 2", "MyType1")); + resourceMap.add(tx, ModelGenerator.createResource("@3", "Resource 3", "MyType1")); + resourceMap.add(tx, ModelGenerator.createResource("@4", "Resource 4", "MyType2")); + resourceMap.add(tx, ModelGenerator.createResource("@5", "Resource 5", "MyType2")); + resourceMap.add(tx, ModelGenerator.createResource("@6", "Resource 6", "MyType2")); + } + } + + @AfterClass + public static void afterClass() { + runtimeMock.destroyRuntime(); + } public Connection openConn() throws SQLException { String url = "jdbc:postgresql://localhost/testdb"; @@ -63,54 +145,110 @@ public class QueryTest { @Test public void shouldQueryOrderAll() throws SQLException { - OrderQuery query = new OrderQuery(new StrolchTypeNavigation("QTestType1")); + OrderQuery query = new OrderQuery(new StrolchTypeNavigation("MyType1")); query.withAny(); - performOrderQuery(query, Arrays.asList("myTestOrder1")); + performOrderQuery(query, Arrays.asList("@1", "@2", "@3")); } @Test public void shouldQueryResourceAll() throws SQLException { - ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType2")); query.withAny(); - performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004")); + performResourceQuery(query, Arrays.asList("@4", "@5", "@6")); + } + + @Test + public void shouldQueryOrderByDate() throws SQLException { + + // range + OrderQuery query = new OrderQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new DateSelection().from(earlier, false).to(later, false)); + performOrderQuery(query, Arrays.asList("@1", "@2", "@3")); + + // equals current + query = new OrderQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new DateSelection().from(current, false).to(current, false)); + performOrderQuery(query, Arrays.asList("@2")); + + // equals later + query = new OrderQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new DateSelection().from(later, false).to(later, false)); + performOrderQuery(query, Arrays. asList("@3")); + + // equals earlier + query = new OrderQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new DateSelection().from(earlier, false).to(earlier, false)); + performOrderQuery(query, Arrays. asList("@1")); + + // past + query = new OrderQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new DateSelection().to(past, false)); + performOrderQuery(query, Arrays. asList()); + + // future + query = new OrderQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new DateSelection().from(future, false)); + performOrderQuery(query, Arrays. asList()); + + // earlier + query = new OrderQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new DateSelection().from(past, false).to(earlier, true)); + performOrderQuery(query, Arrays. asList("@1")); + + // later + query = new OrderQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new DateSelection().from(later, false).to(future, true)); + performOrderQuery(query, Arrays. asList("@3")); + } + + @Test + public void shouldQueryOrderByState() throws SQLException { + + OrderQuery query = new OrderQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new StateSelection(State.CREATED)); + performOrderQuery(query, Arrays.asList("@1")); + + query = new OrderQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new StateSelection(State.OPEN)); + performOrderQuery(query, Arrays. asList("@2")); } @Test public void shouldQueryOrder1() throws SQLException { - OrderQuery query = new OrderQuery(new StrolchTypeNavigation("QTestType1")); - query.and().with(new IdSelection("myTestOrder1", "@2"), - new NameSelection("Test Name", StringMatchMode.EQUALS_CASE_SENSITIVE)); - performOrderQuery(query, Arrays.asList("myTestOrder1")); + OrderQuery query = new OrderQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new IdSelection("@1", "@2"), + new NameSelection("Order 1", StringMatchMode.EQUALS_CASE_SENSITIVE)); + performOrderQuery(query, Arrays.asList("@1")); } @Test public void shouldQueryOrder2() throws SQLException { - OrderQuery query = new OrderQuery(new StrolchTypeNavigation("QTestType1")); - query.or().with(new IdSelection("myTestOrder1", "@2"), - new NameSelection("Test Name", StringMatchMode.EQUALS_CASE_SENSITIVE)); - performOrderQuery(query, Arrays.asList("myTestOrder1")); + OrderQuery query = new OrderQuery(new StrolchTypeNavigation("MyType1")); + query.or().with(new IdSelection("@1", "@2"), + new NameSelection("order 1", StringMatchMode.EQUALS_CASE_SENSITIVE)); + performOrderQuery(query, Arrays.asList("@1", "@2")); } @Test public void shouldQueryResource1() throws SQLException { ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); - query.or().with(new IdSelection("@_00000000", "@_00000001"), - new NameSelection("Test Name", StringMatchMode.EQUALS_CASE_SENSITIVE)); - performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001")); + query.or().with(new IdSelection("@1", "@2"), + new NameSelection("Resource 1", StringMatchMode.EQUALS_CASE_SENSITIVE)); + performResourceQuery(query, Arrays.asList("@1", "@2")); } @Test public void shouldQueryResource2() throws SQLException { ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); query.and().with( - new OrSelection(new IdSelection("@_00000000"), new IdSelection("@_00000001")), - new OrSelection(new NameSelection("My Resource 0", StringMatchMode.EQUALS_CASE_SENSITIVE), - new NameSelection("My Resource 1", StringMatchMode.EQUALS_CASE_SENSITIVE))); - performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001")); + new OrSelection(new IdSelection("@1"), new IdSelection("@2")), + new OrSelection(new NameSelection("Resource 1", StringMatchMode.EQUALS_CASE_SENSITIVE), + new NameSelection("Resource 2", StringMatchMode.EQUALS_CASE_SENSITIVE))); + performResourceQuery(query, Arrays.asList("@1", "@2")); } @Test @@ -127,34 +265,34 @@ public class QueryTest { ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); query.and().with(ParameterSelection.booleanSelection("@bag01", "@param1", true)); - performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004")); + performResourceQuery(query, Arrays.asList("@1", "@2", "@3")); } @Test public void shouldQueryResourceByFloagParam() throws SQLException { ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); query.and().with(ParameterSelection.floatSelection("@bag01", "@param2", 44.3)); - performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004")); + performResourceQuery(query, Arrays.asList("@1", "@2", "@3")); } @Test public void shouldQueryResourceByIntegerParam() throws SQLException { ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); query.and().with(ParameterSelection.integerSelection("@bag01", "@param3", 77)); - performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004")); + performResourceQuery(query, Arrays.asList("@1", "@2", "@3")); } @Test public void shouldQueryResourceByLongParam() throws SQLException { - ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType2")); query.and().with(ParameterSelection.longSelection("@bag01", "@param4", 4453234566L)); - performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004")); + performResourceQuery(query, Arrays.asList("@4", "@5", "@6")); } @Test public void shouldQueryResourceByStringParam() throws SQLException { - List expected = Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004"); + List expected = Arrays.asList("@1", "@2", "@3"); ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); query.and().with( @@ -185,7 +323,7 @@ public class QueryTest { public void shouldQueryResourceByDateParam() throws SQLException { ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); query.and().with(ParameterSelection.dateSelection("@bag01", "@param6", new Date(1354295525628L))); - performResourceQuery(query, Arrays.asList("@_00000000", "@_00000001", "@_00000002", "@_00000003", "@_00000004")); + performResourceQuery(query, Arrays.asList("@1", "@2", "@3")); } @@ -200,7 +338,7 @@ public class QueryTest { PostgreSqlResourceQueryVisitor visitor = new PostgreSqlResourceQueryVisitor("id"); query.accept(visitor); List ids = queryIds(visitor); - assertEquals(expected, ids); + assertEquals(new HashSet<>(expected), new HashSet<>(ids)); } private List queryIds(PostgreSqlQueryVisitor visitor) throws SQLException { From 4cdfb9b6676db4334ab2a7dcf025ab638a89f59b Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 26 Aug 2014 22:07:37 +0200 Subject: [PATCH 56/61] [Devel] adding PostgreSqlAuditQueryVisitor --- .../PostgreSqlAuditQueryVisitor.java | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java new file mode 100644 index 000000000..84290e954 --- /dev/null +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java @@ -0,0 +1,155 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import li.strolch.model.audit.AccessType; +import li.strolch.model.audit.ActionSelection; +import li.strolch.model.audit.AuditQuery; +import li.strolch.model.audit.AuditQueryVisitor; +import li.strolch.model.audit.DateRangeSelection; +import li.strolch.model.audit.ElementSelection; +import li.strolch.model.audit.IdentitySelection; +import li.strolch.model.query.StringSelection; +import ch.eitchnet.utils.StringMatchMode; + +/** + * @author Robert von Burg + */ +public class PostgreSqlAuditQueryVisitor implements AuditQueryVisitor { + + protected StringBuilder sql; + protected StringBuilder sb; + protected List values; + protected String indent; + private String sqlAsString; + + /** + * @param fields + */ + public PostgreSqlAuditQueryVisitor(String fields) { + this.indent = ""; + this.sql = new StringBuilder(); + this.sb = new StringBuilder(); + this.values = new ArrayList<>(); + + this.sql.append("select "); + this.sql.append(fields); + this.sql.append("\nfrom\n"); + this.sql.append(" "); + this.sql.append(PostgreSqlAuditDao.TABLE_NAME); + this.indent = " "; + } + + public String getSql() { + if (sqlAsString != null) + return sqlAsString; + + this.sql.append("\nwhere\n"); + this.sql.append(this.indent); + this.sql.append(this.sb.toString()); + sqlAsString = this.sql.toString(); + return sqlAsString; + } + + @Override + public void visit(ElementSelection selection) { + if (selection.isWildcard()) + return; + + if (!selection.isElementsAccessedWildcard()) { + StringSelection sel = selection.getElementAccessedSelection(); + toSql(sel.getMatchMode(), sel.getValues()); + } + + if (!selection.isElementTypesWildcard()) { + StringSelection sel = selection.getElementTypeSelection(); + toSql(sel.getMatchMode(), sel.getValues()); + } + } + + private void toSql(StringMatchMode mm, String[] values) { + this.sb.append(this.indent); + this.sb.append(PostgreSqlHelper.toSql(this.indent, mm, this.values, values)); + } + + @Override + public void visit(IdentitySelection selection) { + if (selection.isWildcard()) + return; + + if (!selection.isFirstnameWildcard()) { + StringSelection sel = selection.getFirstnameSelection(); + toSql(sel.getMatchMode(), sel.getValues()); + } + + if (!selection.isLastnameWildcard()) { + StringSelection sel = selection.getLastnameSelection(); + toSql(sel.getMatchMode(), sel.getValues()); + } + + if (!selection.isUsernameWildcard()) { + StringSelection sel = selection.getUsernameSelection(); + toSql(sel.getMatchMode(), sel.getValues()); + } + } + + @Override + public void visit(DateRangeSelection selection) { + + // TODO Auto-generated method stub + + } + + @Override + public void visit(ActionSelection selection) { + if (!selection.isWildcardAction()) { + StringSelection sel = selection.getActionSelection(); + toSql(sel.getMatchMode(), sel.getValues()); + } + + if (!selection.isWildcardActionType()) { + + AccessType[] accessTypes = selection.getAccessTypes(); + String[] query = new String[accessTypes.length]; + for (int i = 0; i < accessTypes.length; i++) { + query[i] = accessTypes[i].name(); + } + + toSql(StringMatchMode.EQUALS_CASE_SENSITIVE, query); + } + } + + @Override + public void visit(AuditQuery auditQuery) { + // TODO Auto-generated method stub + + } + + /** + * @param ps + * @throws SQLException + */ + public void setValues(PreparedStatement ps) throws SQLException { + for (int i = 0; i < this.values.size(); i++) { + ps.setObject(i + 1, this.values.get(i)); + } + } +} From 7f5f20721464106789c30a15ac9738102d83c87b Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Thu, 28 Aug 2014 21:46:44 +0200 Subject: [PATCH 57/61] [Major] Implemented PostgreSql AuditQuery --- .../postgresql/PostgreSqlAuditDao.java | 37 ++- .../PostgreSqlAuditQueryVisitor.java | 89 +++--- .../postgresql/PostgreSqlHelper.java | 64 +++-- .../PostgreSqlOrderQueryVisitor.java | 26 +- .../postgresql/PostgreSqlQueryVisitor.java | 2 +- .../postgresql/dao/test/AuditQueryTest.java | 270 ++++++++++++++++++ .../postgresql/dao/test/CachedDaoTest.java | 9 + .../postgresql/dao/test/QueryTest.java | 2 +- 8 files changed, 402 insertions(+), 97 deletions(-) create mode 100644 src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java index 95120e07e..c56c7cf1b 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java @@ -33,13 +33,26 @@ import li.strolch.model.audit.AuditVisitor; import li.strolch.persistence.api.AuditDao; import li.strolch.persistence.api.StrolchPersistenceException; import ch.eitchnet.utils.collections.DateRange; +import ch.eitchnet.utils.helper.StringHelper; /** * @author Robert von Burg */ public class PostgreSqlAuditDao implements AuditDao { - public static final String FIELDS = "id, username, firstname, lastname, date, element_type, element_accessed, new_version, action, access_type"; + public static final String ID = "id"; + public static final String ACCESS_TYPE = "access_type"; + public static final String ACCESS_TYPE_TYPE = "::access_type"; + public static final String ACTION = "action"; + public static final String NEW_VERSION = "new_version"; + public static final String ELEMENT_ACCESSED = "element_accessed"; + public static final String ELEMENT_TYPE = "element_type"; + public static final String DATE = "date"; + public static final String LASTNAME = "lastname"; + public static final String FIRSTNAME = "firstname"; + public static final String USERNAME = "username"; + public static final String FIELDS = StringHelper.commaSeparated(ID, USERNAME, FIRSTNAME, LASTNAME, DATE, + ELEMENT_TYPE, ELEMENT_ACCESSED, NEW_VERSION, ACTION, ACCESS_TYPE); public static final String TABLE_NAME = "audits"; private PostgreSqlStrolchTransaction tx; @@ -53,7 +66,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public boolean hasElement(String type, Long id) { - String sql = "select count(*) from " + TABLE_NAME + " where element_type = ? and id = ?"; //$NON-NLS-1$ + String sql = "select count(*) from " + TABLE_NAME + " where " + ELEMENT_TYPE + " = ? and " + ID + " = ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); @@ -78,7 +91,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public long querySize(DateRange dateRange) { - String sql = "select count(*) from " + TABLE_NAME + " where date between ? and ?"; //$NON-NLS-1$ + String sql = "select count(*) from " + TABLE_NAME + " where " + DATE + " between ? and ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setDate(1, new Date(dateRange.getFromDate().getTime()), Calendar.getInstance()); @@ -96,7 +109,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public long querySize(String type, DateRange dateRange) { - String sql = "select count(*) from " + TABLE_NAME + " where element_type = ? and date between ? and ?"; //$NON-NLS-1$ + String sql = "select count(*) from " + TABLE_NAME + " where " + ELEMENT_TYPE + " = ? and " + DATE + " between ? and ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); @@ -117,11 +130,11 @@ public class PostgreSqlAuditDao implements AuditDao { public Set queryTypes() { Set keySet = new HashSet<>(); - String sql = "select distinct element_type from " + TABLE_NAME; //$NON-NLS-1$ + String sql = "select distinct " + ELEMENT_TYPE + " from " + TABLE_NAME; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { try (ResultSet result = statement.executeQuery()) { while (result.next()) { - keySet.add(result.getString("element_type")); //$NON-NLS-1$ + keySet.add(result.getString(ELEMENT_TYPE)); //$NON-NLS-1$ } } } catch (SQLException e) { @@ -134,7 +147,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public Audit queryBy(String type, Long id) { - String sql = "select " + FIELDS + " from " + TABLE_NAME + " where element_type = ? and id = ?"; //$NON-NLS-1$ + String sql = "select " + FIELDS + " from " + TABLE_NAME + " where " + ELEMENT_TYPE + " = ? and " + ID + " = ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); @@ -157,7 +170,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public List queryAll(String type, DateRange dateRange) { List list = new ArrayList<>(); - String sql = "select " + FIELDS + " from " + TABLE_NAME + " where element_type = ? and date between ? and ?"; //$NON-NLS-1$ + String sql = "select " + FIELDS + " from " + TABLE_NAME + " where " + ELEMENT_TYPE + " = ? and " + DATE + " between ? and ?"; //$NON-NLS-1$ try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { statement.setString(1, type); @@ -205,7 +218,9 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public void update(Audit audit) { - String sql = "update " + TABLE_NAME + " set id = ?, username = ?, firstname = ?, lastname = ?, date = ?, element_type = ?, element_accessed = ?, new_version = ?, action = ?, access_type = ?::access_type where id = ?"; //$NON-NLS-1$ + String sql = "update " + TABLE_NAME + " set " + ID + " = ?, " + USERNAME + " = ?, " + FIRSTNAME + " = ?, " + + LASTNAME + " = ?, " + DATE + " = ?, " + ELEMENT_TYPE + " = ?, " + ELEMENT_ACCESSED + " = ?, " + + NEW_VERSION + " = ?, " + ACTION + " = ?, " + ACCESS_TYPE + " = ?::access_type where " + ID + " = ?"; //$NON-NLS-1$ try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { setAuditFields(audit, preparedStatement); @@ -232,7 +247,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public void remove(Audit audit) { - String sql = "delete from " + TABLE_NAME + " where id = ?"; //$NON-NLS-1$ + String sql = "delete from " + TABLE_NAME + " where " + ID + " = ?"; //$NON-NLS-1$ try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { preparedStatement.setLong(1, audit.getId()); @@ -259,7 +274,7 @@ public class PostgreSqlAuditDao implements AuditDao { @Override public long removeAll(String type, DateRange dateRange) { - String sql = "delete from " + TABLE_NAME + " where element_type = ? and date between ? and ?"; //$NON-NLS-1$ + String sql = "delete from " + TABLE_NAME + " where " + ELEMENT_TYPE + " = ? and " + DATE + " between ? and ?"; //$NON-NLS-1$ try (PreparedStatement preparedStatement = this.tx.getConnection().prepareStatement(sql)) { preparedStatement.setString(1, type); diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java index 84290e954..c43d91d48 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java @@ -24,7 +24,6 @@ import li.strolch.model.audit.AccessType; import li.strolch.model.audit.ActionSelection; import li.strolch.model.audit.AuditQuery; import li.strolch.model.audit.AuditQueryVisitor; -import li.strolch.model.audit.DateRangeSelection; import li.strolch.model.audit.ElementSelection; import li.strolch.model.audit.IdentitySelection; import li.strolch.model.query.StringSelection; @@ -63,31 +62,28 @@ public class PostgreSqlAuditQueryVisitor implements AuditQueryVisitor { return sqlAsString; this.sql.append("\nwhere\n"); - this.sql.append(this.indent); this.sql.append(this.sb.toString()); sqlAsString = this.sql.toString(); return sqlAsString; } @Override - public void visit(ElementSelection selection) { - if (selection.isWildcard()) - return; - - if (!selection.isElementsAccessedWildcard()) { - StringSelection sel = selection.getElementAccessedSelection(); - toSql(sel.getMatchMode(), sel.getValues()); - } - - if (!selection.isElementTypesWildcard()) { - StringSelection sel = selection.getElementTypeSelection(); - toSql(sel.getMatchMode(), sel.getValues()); - } + public void visit(AuditQuery auditQuery) { + ensureAnd(); + this.sb.append(this.indent); + this.sb.append(PostgreSqlAuditDao.ELEMENT_TYPE); + this.sb.append(" = ?\n"); + ensureAnd(); + this.values.add(auditQuery.getElementTypeSelection()); + PostgreSqlHelper.toSql(this.indent, this.sb, this.values, PostgreSqlAuditDao.DATE, auditQuery.getDateRange()); } - private void toSql(StringMatchMode mm, String[] values) { - this.sb.append(this.indent); - this.sb.append(PostgreSqlHelper.toSql(this.indent, mm, this.values, values)); + @Override + public void visit(ElementSelection selection) { + if (!selection.isElementsAccessedWildcard()) { + StringSelection sel = selection.getElementAccessedSelection(); + toSql(PostgreSqlAuditDao.ELEMENT_ACCESSED, sel.getMatchMode(), sel.getValues()); + } } @Override @@ -97,59 +93,68 @@ public class PostgreSqlAuditQueryVisitor implements AuditQueryVisitor { if (!selection.isFirstnameWildcard()) { StringSelection sel = selection.getFirstnameSelection(); - toSql(sel.getMatchMode(), sel.getValues()); + toSql(PostgreSqlAuditDao.FIRSTNAME, sel.getMatchMode(), sel.getValues()); } if (!selection.isLastnameWildcard()) { StringSelection sel = selection.getLastnameSelection(); - toSql(sel.getMatchMode(), sel.getValues()); + toSql(PostgreSqlAuditDao.LASTNAME, sel.getMatchMode(), sel.getValues()); } if (!selection.isUsernameWildcard()) { StringSelection sel = selection.getUsernameSelection(); - toSql(sel.getMatchMode(), sel.getValues()); + toSql(PostgreSqlAuditDao.USERNAME, sel.getMatchMode(), sel.getValues()); } } - @Override - public void visit(DateRangeSelection selection) { - - // TODO Auto-generated method stub - - } - @Override public void visit(ActionSelection selection) { if (!selection.isWildcardAction()) { StringSelection sel = selection.getActionSelection(); - toSql(sel.getMatchMode(), sel.getValues()); + toSql(PostgreSqlAuditDao.ACTION, sel.getMatchMode(), sel.getValues()); } if (!selection.isWildcardActionType()) { AccessType[] accessTypes = selection.getAccessTypes(); - String[] query = new String[accessTypes.length]; - for (int i = 0; i < accessTypes.length; i++) { - query[i] = accessTypes[i].name(); + ensureAnd(); + this.sb.append(this.indent); + if (accessTypes.length == 1) { + sb.append(PostgreSqlAuditDao.ACCESS_TYPE + " = ?"); + sb.append(PostgreSqlAuditDao.ACCESS_TYPE_TYPE); + sb.append("\n"); + this.values.add(accessTypes[0].name()); + } else { + sb.append(PostgreSqlAuditDao.ACCESS_TYPE + " in ("); + for (int i = 0; i < accessTypes.length; i++) { + sb.append("?"); + sb.append(PostgreSqlAuditDao.ACCESS_TYPE_TYPE); + values.add(accessTypes[i].name()); + if (i < accessTypes.length - 1) + sb.append(", "); + } + sb.append(" )\n"); + sb.append("\n"); } - - toSql(StringMatchMode.EQUALS_CASE_SENSITIVE, query); } } - @Override - public void visit(AuditQuery auditQuery) { - // TODO Auto-generated method stub - + private void toSql(String column, StringMatchMode mm, String[] values) { + ensureAnd(); + this.sb.append(this.indent); + this.sb.append(PostgreSqlHelper.toSql(column, this.indent, mm, this.values, values)); } - /** - * @param ps - * @throws SQLException - */ public void setValues(PreparedStatement ps) throws SQLException { for (int i = 0; i < this.values.size(); i++) { ps.setObject(i + 1, this.values.get(i)); } } + + private void ensureAnd() { + if (this.sb.length() > 0) { + this.sb.append(this.indent); + this.sb.append("and \n"); + } + } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java index 9bcec7a27..b552d9e2d 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java @@ -15,17 +15,47 @@ */ package li.strolch.persistence.postgresql; +import java.sql.Date; import java.util.ArrayList; import java.util.List; import ch.eitchnet.utils.StringMatchMode; +import ch.eitchnet.utils.collections.DateRange; /** * @author Robert von Burg */ public class PostgreSqlHelper { - public static String toSql(String indent, StringMatchMode mm, List values, String... query) { + public static void toSql(String indent, StringBuilder sb, List values, String column, DateRange dateRange) { + + // TODO handle inclusive/exclusive: between is inclusive + + if (dateRange.isDate()) { + sb.append(indent); + sb.append(column); + sb.append(" = ?\n"); + values.add(new Date(dateRange.getFromDate().getTime())); + } else if (dateRange.isBounded()) { + sb.append(indent); + sb.append(column); + sb.append(" between ? and ?\n"); + values.add(new Date(dateRange.getFromDate().getTime())); + values.add(new Date(dateRange.getToDate().getTime())); + } else if (dateRange.isToBounded()) { + sb.append(indent); + sb.append(column); + sb.append(" <= ?\n"); + values.add(new Date(dateRange.getToDate().getTime())); + } else if (dateRange.isFromBounded()) { + sb.append(indent); + sb.append(column); + sb.append(" >= ?\n"); + values.add(new Date(dateRange.getFromDate().getTime())); + } + } + + public static String toSql(String column, String indent, StringMatchMode mm, List values, String... query) { // CS EQ // 1. x x @@ -36,10 +66,10 @@ public class PostgreSqlHelper { StringBuilder sb = new StringBuilder(); if (mm.isCaseSensitve() && mm.isEquals()) { if (query.length == 1) { - sb.append("name = ?\n"); + sb.append(column + " = ?\n"); values.add(query[0]); } else { - sb.append("name in ( "); + sb.append(column + " in ( "); for (int i = 0; i < query.length; i++) { sb.append("?"); values.add(query[i]); @@ -50,10 +80,10 @@ public class PostgreSqlHelper { } } else if (!mm.isCaseSensitve() && mm.isEquals()) { if (query.length == 1) { - sb.append("lower(name) = ?\n"); + sb.append("lower(" + column + ") = ?\n"); values.add(query[0].toLowerCase()); } else { - sb.append("lower(name) in ( "); + sb.append("lower(" + column + ") in ( "); for (int i = 0; i < query.length; i++) { sb.append("?"); values.add(query[i].toLowerCase()); @@ -64,14 +94,14 @@ public class PostgreSqlHelper { } } else if (!mm.isEquals() && mm.isCaseSensitve()) { if (query.length == 1) { - sb.append("name like ?\n"); + sb.append(column + " like ?\n"); values.add("%" + query[0] + "%"); } else { sb.append("(\n"); for (int i = 0; i < query.length; i++) { sb.append(indent); sb.append(" "); - sb.append("name like ?"); + sb.append(column + " like ?"); values.add("%" + query[i] + "%"); if (i < query.length - 1) sb.append(" or"); @@ -81,14 +111,14 @@ public class PostgreSqlHelper { } } else { if (query.length == 1) { - sb.append("lower(name) like ?\n"); + sb.append("lower(" + column + ") like ?\n"); values.add("%" + query[0].toLowerCase() + "%"); } else { sb.append("(\n"); for (int i = 0; i < query.length; i++) { sb.append(indent); sb.append(" "); - sb.append("lower(name) like ?"); + sb.append("lower(" + column + ") like ?"); values.add("%" + query[i].toLowerCase() + "%"); if (i < query.length - 1) sb.append(" or"); @@ -103,35 +133,35 @@ public class PostgreSqlHelper { public static void main(String[] args) { ArrayList values = new ArrayList<>(); - String sql = toSql(" ", StringMatchMode.CONTAINS_CASE_INSENSITIVE, values, "foo", "bar", "fub"); + String sql = toSql("name", " ", StringMatchMode.CONTAINS_CASE_INSENSITIVE, values, "foo", "bar", "fub"); System.out.println(sql); System.out.println(); - sql = toSql(" ", StringMatchMode.CONTAINS_CASE_INSENSITIVE, values, "foo"); + sql = toSql("name", " ", StringMatchMode.CONTAINS_CASE_INSENSITIVE, values, "foo"); System.out.println(sql); System.out.println(); - sql = toSql(" ", StringMatchMode.CONTAINS_CASE_SENSITIVE, values, "foo", "bar", "fub"); + sql = toSql("name", " ", StringMatchMode.CONTAINS_CASE_SENSITIVE, values, "foo", "bar", "fub"); System.out.println(sql); System.out.println(); - sql = toSql(" ", StringMatchMode.CONTAINS_CASE_SENSITIVE, values, "foo"); + sql = toSql("name", " ", StringMatchMode.CONTAINS_CASE_SENSITIVE, values, "foo"); System.out.println(sql); System.out.println(); - sql = toSql(" ", StringMatchMode.EQUALS_CASE_INSENSITIVE, values, "foo", "bar", "fub"); + sql = toSql("name", " ", StringMatchMode.EQUALS_CASE_INSENSITIVE, values, "foo", "bar", "fub"); System.out.println(sql); System.out.println(); - sql = toSql(" ", StringMatchMode.EQUALS_CASE_INSENSITIVE, values, "foo"); + sql = toSql("name", " ", StringMatchMode.EQUALS_CASE_INSENSITIVE, values, "foo"); System.out.println(sql); System.out.println(); - sql = toSql(" ", StringMatchMode.EQUALS_CASE_SENSITIVE, values, "foo", "bar", "fub"); + sql = toSql("name", " ", StringMatchMode.EQUALS_CASE_SENSITIVE, values, "foo", "bar", "fub"); System.out.println(sql); System.out.println(); - sql = toSql(" ", StringMatchMode.EQUALS_CASE_SENSITIVE, values, "foo"); + sql = toSql("name", " ", StringMatchMode.EQUALS_CASE_SENSITIVE, values, "foo"); System.out.println(sql); System.out.println(); } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java index ec8f728f0..687ac1331 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java @@ -15,13 +15,10 @@ */ package li.strolch.persistence.postgresql; -import java.sql.Date; - import li.strolch.model.Tags; import li.strolch.model.query.DateSelection; import li.strolch.model.query.OrderQueryVisitor; import li.strolch.model.query.StateSelection; -import ch.eitchnet.utils.collections.DateRange; /** * @author Robert von Burg @@ -45,28 +42,7 @@ public class PostgreSqlOrderQueryVisitor extends PostgreSqlQueryVisitor implemen @Override public void visit(DateSelection selection) { - - // TODO handle inclusive and exclusive date ranges - - DateRange dateRange = selection.getDateRange(); - if (dateRange.isDate()) { - sb.append(indent); - sb.append("date = ?\n"); - values.add(new Date(dateRange.getFromDate().getTime())); - } else if (dateRange.isBounded()) { - sb.append(indent); - sb.append("date between ? and ?\n"); - values.add(new Date(dateRange.getFromDate().getTime())); - values.add(new Date(dateRange.getToDate().getTime())); - } else if (dateRange.isToBounded()) { - sb.append(indent); - sb.append("date < ?\n"); - values.add(new Date(dateRange.getToDate().getTime())); - } else if (dateRange.isFromBounded()) { - sb.append(indent); - sb.append("date > ?\n"); - values.add(new Date(dateRange.getFromDate().getTime())); - } + PostgreSqlHelper.toSql(this.indent, this.sb, this.values, "date", selection.getDateRange()); } @Override diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java index f5d1e015e..c10debcbe 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java @@ -144,7 +144,7 @@ public abstract class PostgreSqlQueryVisitor implements StrolchElementSelectionV this.sb.append(this.indent); String name = selection.getName(); StringMatchMode mm = selection.getMatchMode(); - this.sb.append(toSql(this.indent, mm, this.values, name)); + this.sb.append(toSql("name", this.indent, mm, this.values, name)); } @Override diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java new file mode 100644 index 000000000..a85cc67f0 --- /dev/null +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java @@ -0,0 +1,270 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql.dao.test; + +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.CONFIG_SRC; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_PASSWORD; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_STORE_PATH_DIR; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_URL; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_USERNAME; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.RUNTIME_PATH; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.dropSchema; +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.List; + +import li.strolch.agent.api.AuditTrail; +import li.strolch.agent.api.StrolchRealm; +import li.strolch.model.ModelGenerator; +import li.strolch.model.Tags; +import li.strolch.model.audit.AccessType; +import li.strolch.model.audit.Audit; +import li.strolch.model.audit.AuditQuery; +import li.strolch.persistence.api.AbstractTransaction; +import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.persistence.postgresql.PostgreSqlAuditQueryVisitor; +import li.strolch.runtime.StrolchConstants; +import li.strolch.testbase.runtime.RuntimeMock; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ch.eitchnet.privilege.model.Certificate; +import ch.eitchnet.utils.StringMatchMode; +import ch.eitchnet.utils.collections.DateRange; + +/** + * @author Robert von Burg + */ +public class AuditQueryTest { + + private static final Logger logger = LoggerFactory.getLogger(AuditQueryTest.class); + private static RuntimeMock runtimeMock; + + private static Date past; + private static Date earlier; + private static Date current; + private static Date later; + private static Date future; + + @BeforeClass + public static void beforeClass() throws SQLException { + + dropSchema(DB_URL, DB_USERNAME, DB_PASSWORD); + + File rootPath = new File(RUNTIME_PATH); + File configSrc = new File(CONFIG_SRC); + runtimeMock = new RuntimeMock(); + runtimeMock.mockRuntime(rootPath, configSrc); + new File(rootPath, DB_STORE_PATH_DIR).mkdir(); + runtimeMock.startContainer(); + + Calendar cal = Calendar.getInstance(); + cal.clear(); + cal.set(2000, 1, 1); + past = cal.getTime(); + cal.set(2000, 4, 1); + earlier = cal.getTime(); + cal.set(2000, 6, 1); + current = cal.getTime(); + cal.set(2000, 8, 1); + later = cal.getTime(); + cal.set(2000, 11, 1); + future = cal.getTime(); + + Certificate cert = runtimeMock.getPrivilegeHandler().authenticate("test", "test".getBytes()); + StrolchRealm realm = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM); + int i = 0; + try (StrolchTransaction tx = realm.openTx(cert, "test")) { + ((AbstractTransaction) tx).setSuppressAudits(true); + AuditTrail auditTrail = tx.getAuditTrail(); + + Audit randomAudit; + randomAudit = ModelGenerator.randomAudit(); + randomAudit.setId(i++); + randomAudit.setUsername("earlier"); + randomAudit.setDate(earlier); + randomAudit.setAccessType(AccessType.CREATE); + randomAudit.setAction("create"); + randomAudit.setElementAccessed(randomAudit.getAccessType().name()); + auditTrail.add(tx, randomAudit); + + randomAudit = ModelGenerator.randomAudit(); + randomAudit.setId(i++); + randomAudit.setDate(current); + randomAudit.setUsername("current"); + randomAudit.setAccessType(AccessType.READ); + randomAudit.setAction("read"); + randomAudit.setElementAccessed(randomAudit.getAccessType().name()); + auditTrail.add(tx, randomAudit); + + randomAudit = ModelGenerator.randomAudit(); + randomAudit.setId(i++); + randomAudit.setDate(later); + randomAudit.setUsername("later"); + randomAudit.setAccessType(AccessType.UPDATE); + randomAudit.setAction("update"); + randomAudit.setElementAccessed(randomAudit.getAccessType().name()); + auditTrail.add(tx, randomAudit); + + randomAudit = ModelGenerator.randomAudit(); + randomAudit.setId(i++); + randomAudit.setDate(current); + randomAudit.setUsername("current"); + randomAudit.setAccessType(AccessType.DELETE); + randomAudit.setAction("delete"); + randomAudit.setElementAccessed(randomAudit.getAccessType().name()); + auditTrail.add(tx, randomAudit); + + randomAudit = ModelGenerator.randomAudit(); + randomAudit.setId(i++); + randomAudit.setDate(current); + randomAudit.setUsername("current"); + randomAudit.setAccessType(AccessType.CREATE); + randomAudit.setAction("create"); + randomAudit.setElementAccessed(randomAudit.getAccessType().name()); + auditTrail.add(tx, randomAudit); + } + } + + @AfterClass + public static void afterClass() { + runtimeMock.destroyRuntime(); + } + + public Connection openConn() throws SQLException { + String url = "jdbc:postgresql://localhost/testdb"; + String username = "testuser"; + String password = "test"; + Connection connection = DriverManager.getConnection(url, username, password); + connection.setAutoCommit(false); + return connection; + } + + @Test + public void shouldQueryTypeAndDateRange() throws SQLException { + AuditQuery query = new AuditQuery(Tags.AUDIT, new DateRange().from(earlier, true).to(later, true)); + performQuery(query, Arrays.asList("0", "1", "2", "3", "4")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(current, true).to(current, true)); + performQuery(query, Arrays.asList("1", "3", "4")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(current, true)); + performQuery(query, Arrays.asList("1", "2", "3", "4")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().to(current, true)); + performQuery(query, Arrays.asList("0", "1", "3", "4")); + + query = new AuditQuery(Tags.RESOURCE, new DateRange().from(past, true).to(future, true)); + performQuery(query, Arrays. asList()); + } + + @Test + public void shouldQueryAudits() throws SQLException { + AuditQuery query = new AuditQuery(Tags.AUDIT, new DateRange().from(past, true).to(future, true)); + query.action().accessTypes(AccessType.CREATE, AccessType.READ); + performQuery(query, Arrays.asList("0", "1", "4")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(past, true).to(future, true)); + query.action().accessTypes(AccessType.CREATE); + performQuery(query, Arrays.asList("0", "4")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(past, true).to(future, true)); + query.action().accessTypes(AccessType.CREATE, AccessType.READ) + .actions(StringMatchMode.EQUALS_CASE_SENSITIVE, "create", "read"); + performQuery(query, Arrays.asList("0", "1", "4")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(past, true).to(future, true)); + query.action().accessTypes(AccessType.CREATE, AccessType.READ) + .actions(StringMatchMode.EQUALS_CASE_SENSITIVE, "read"); + performQuery(query, Arrays.asList("1")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(past, true).to(future, true)); + query.element().elementsAccessed(StringMatchMode.CONTAINS_CASE_INSENSITIVE, "crea"); + performQuery(query, Arrays.asList("0", "4")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(past, true).to(future, true)); + query.element().elementsAccessed(StringMatchMode.CONTAINS_CASE_SENSITIVE, "crea"); + performQuery(query, Arrays. asList()); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(past, true).to(future, true)); + query.element().elementsAccessed(StringMatchMode.EQUALS_CASE_INSENSITIVE, "create"); + performQuery(query, Arrays.asList("0", "4")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(past, true).to(future, true)); + query.identity().usernames(StringMatchMode.EQUALS_CASE_INSENSITIVE, "earlier"); + performQuery(query, Arrays.asList("0")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(past, true).to(future, true)); + query.identity().usernames(StringMatchMode.EQUALS_CASE_INSENSITIVE, "earlier", "later"); + performQuery(query, Arrays.asList("0", "2")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(past, true).to(future, true)); + query.identity().usernames(StringMatchMode.EQUALS_CASE_INSENSITIVE, "earlier") + .firstnames(StringMatchMode.CONTAINS_CASE_INSENSITIVE, "enn"); + performQuery(query, Arrays.asList("0")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(past, true).to(future, true)); + query.identity().usernames(StringMatchMode.EQUALS_CASE_INSENSITIVE, "earlier") + .firstnames(StringMatchMode.CONTAINS_CASE_INSENSITIVE, "enn") + .lastnames(StringMatchMode.CONTAINS_CASE_INSENSITIVE, "kennedy"); + performQuery(query, Arrays.asList("0")); + + query = new AuditQuery(Tags.AUDIT, new DateRange().from(past, true).to(future, true)); + query.identity().firstnames(StringMatchMode.CONTAINS_CASE_INSENSITIVE, "enn") + .lastnames(StringMatchMode.CONTAINS_CASE_INSENSITIVE, "kennedy"); + performQuery(query, Arrays.asList("0", "1", "2", "3", "4")); + } + + private void performQuery(AuditQuery query, List expected) throws SQLException { + PostgreSqlAuditQueryVisitor visitor = new PostgreSqlAuditQueryVisitor("id"); + query.accept(visitor); + List ids = queryIds(visitor); + assertEquals(new HashSet<>(expected), new HashSet<>(ids)); + } + + private List queryIds(PostgreSqlAuditQueryVisitor visitor) throws SQLException { + String sql = visitor.getSql(); + logger.info("\n" + sql); + List ids = new ArrayList<>(); + try (Connection con = openConn()) { + try (PreparedStatement ps = con.prepareStatement(sql)) { + visitor.setValues(ps); + + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + ids.add(rs.getString(1)); + } + } + } + + return ids; + } +} diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java index f689524ed..902e86e26 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java @@ -19,6 +19,7 @@ import java.io.File; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; +import java.text.MessageFormat; import li.strolch.persistence.postgresql.DbSchemaVersionCheck; import li.strolch.testbase.runtime.AbstractModelTest; @@ -26,6 +27,10 @@ import li.strolch.testbase.runtime.RuntimeMock; import org.junit.AfterClass; import org.junit.BeforeClass; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ch.eitchnet.utils.helper.StringHelper; public class CachedDaoTest extends AbstractModelTest { @@ -37,6 +42,8 @@ public class CachedDaoTest extends AbstractModelTest { public static final String DB_USERNAME = "testuser"; //$NON-NLS-1$ public static final String DB_PASSWORD = "test"; //$NON-NLS-1$ + private static final Logger logger = LoggerFactory.getLogger(CachedDaoTest.class); + protected static RuntimeMock runtimeMock; @Override @@ -59,7 +66,9 @@ public class CachedDaoTest extends AbstractModelTest { public static void dropSchema(String dbUrl, String dbUsername, String dbPassword) throws SQLException { String dbVersion = DbSchemaVersionCheck.getExpectedDbVersion(); + logger.info(MessageFormat.format("Dropping schema for expected version {0}", dbVersion)); String sql = DbSchemaVersionCheck.getSql(dbVersion, "drop"); //$NON-NLS-1$ + logger.info(StringHelper.NEW_LINE + sql); try (Connection connection = DriverManager.getConnection(dbUrl, dbUsername, dbPassword)) { connection.prepareStatement(sql).execute(); } diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java index 596990f7c..88c9afdfb 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java @@ -331,7 +331,7 @@ public class QueryTest { PostgreSqlOrderQueryVisitor visitor = new PostgreSqlOrderQueryVisitor("id"); query.accept(visitor); List ids = queryIds(visitor); - assertEquals(expected, ids); + assertEquals(new HashSet<>(expected), new HashSet<>(ids)); } private void performResourceQuery(ResourceQuery query, List expected) throws SQLException { From 71973e85970e26621ae143b2a995ec8720a12265 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Thu, 4 Sep 2014 20:30:40 +0200 Subject: [PATCH 58/61] [New] Implemented param null selector and ParameterBagSelector --- .../postgresql/PostgreSqlQueryVisitor.java | 32 +++++++++++++++++-- .../postgresql/dao/test/QueryTest.java | 29 +++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java index c10debcbe..b552746e6 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java @@ -28,17 +28,20 @@ import li.strolch.model.query.IdSelection; import li.strolch.model.query.NameSelection; import li.strolch.model.query.NotSelection; import li.strolch.model.query.OrSelection; +import li.strolch.model.query.ParameterBagSelection; +import li.strolch.model.query.ParameterBagSelection.NullParameterBagSelection; import li.strolch.model.query.ParameterSelection.BooleanParameterSelection; import li.strolch.model.query.ParameterSelection.DateParameterSelection; import li.strolch.model.query.ParameterSelection.DateRangeParameterSelection; import li.strolch.model.query.ParameterSelection.FloatParameterSelection; import li.strolch.model.query.ParameterSelection.IntegerParameterSelection; import li.strolch.model.query.ParameterSelection.LongParameterSelection; +import li.strolch.model.query.ParameterSelection.NullParameterSelection; import li.strolch.model.query.ParameterSelection.StringListParameterSelection; import li.strolch.model.query.ParameterSelection.StringParameterSelection; import li.strolch.model.query.ParameterSelectionVisitor; import li.strolch.model.query.Selection; -import li.strolch.model.query.StrolchElementSelectionVisitor; +import li.strolch.model.query.StrolchRootElementSelectionVisitor; import li.strolch.model.query.StrolchTypeNavigation; import ch.eitchnet.utils.StringMatchMode; import ch.eitchnet.utils.dbc.DBC; @@ -47,7 +50,7 @@ import ch.eitchnet.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg */ -public abstract class PostgreSqlQueryVisitor implements StrolchElementSelectionVisitor, ParameterSelectionVisitor { +public abstract class PostgreSqlQueryVisitor implements StrolchRootElementSelectionVisitor, ParameterSelectionVisitor { protected StringBuilder sql; protected StringBuilder sb; @@ -298,6 +301,31 @@ public abstract class PostgreSqlQueryVisitor implements StrolchElementSelectionV ISO8601FormatFactory.getInstance().formatDate(selection.getValue())); } + @Override + public void visit(NullParameterSelection selection) { + String xpath = "cast(xpath('//Resource/ParameterBag[@Id=\"${bagKey}\"]/Parameter[@Id=\"${paramKey}\"]', asxml) as text[]) = '{}'\n"; + this.sb.append(this.indent); + xpath = xpath.replace("${bagKey}", selection.getBagKey()); + xpath = xpath.replace("${paramKey}", selection.getParamKey()); + this.sb.append(xpath); + } + + @Override + public void visit(ParameterBagSelection selection) { + String xpath = "cast(xpath('//Resource/ParameterBag[@Id=\"${bagKey}\"]', asxml) as text[]) != '{}'\n"; + this.sb.append(this.indent); + xpath = xpath.replace("${bagKey}", selection.getBagKey()); + this.sb.append(xpath); + } + + @Override + public void visit(NullParameterBagSelection selection) { + String xpath = "cast(xpath('//Resource/ParameterBag[@Id=\"${bagKey}\"]', asxml) as text[]) = '{}'\n"; + this.sb.append(this.indent); + xpath = xpath.replace("${bagKey}", selection.getBagKey()); + this.sb.append(xpath); + } + @Override public void visit(DateRangeParameterSelection selection) { throw new UnsupportedOperationException("Not yet supported!"); diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java b/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java index 88c9afdfb..328d00f36 100644 --- a/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java +++ b/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java @@ -47,6 +47,8 @@ import li.strolch.model.query.IdSelection; import li.strolch.model.query.NameSelection; import li.strolch.model.query.OrSelection; import li.strolch.model.query.OrderQuery; +import li.strolch.model.query.ParameterBagSelection; +import li.strolch.model.query.ParameterBagSelection.NullParameterBagSelection; import li.strolch.model.query.ParameterSelection; import li.strolch.model.query.ResourceQuery; import li.strolch.model.query.StateSelection; @@ -324,7 +326,34 @@ public class QueryTest { ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); query.and().with(ParameterSelection.dateSelection("@bag01", "@param6", new Date(1354295525628L))); performResourceQuery(query, Arrays.asList("@1", "@2", "@3")); + } + @Test + public void shouldQueryResourceByNullParam1() throws SQLException { + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(ParameterSelection.nullSelection("@bag01", "@param6")); + performResourceQuery(query, Arrays. asList()); + } + + @Test + public void shouldQueryResourceByNullParam2() throws SQLException { + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(ParameterSelection.nullSelection("@bag01", "@param")); + performResourceQuery(query, Arrays.asList("@1", "@2", "@3")); + } + + @Test + public void shouldQueryResourceByBag() throws SQLException { + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new ParameterBagSelection("@bag01")); + performResourceQuery(query, Arrays.asList("@1", "@2", "@3")); + } + + @Test + public void shouldQueryResourceByNullBag() throws SQLException { + ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType1")); + query.and().with(new NullParameterBagSelection("@bag01")); + performResourceQuery(query, Arrays. asList()); } private void performOrderQuery(OrderQuery query, List expected) throws SQLException { From 376278cc25cd5033bc77401917b9dd83f4c9225f Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 8 Sep 2014 13:35:57 +0200 Subject: [PATCH 59/61] [New] Added privilege checking for StrolchQueries --- .../postgresql/PostgreSqlPersistenceHandler.java | 2 +- .../postgresql/PostgreSqlStrolchTransaction.java | 7 ++++--- src/test/resources/cachedruntime/config/PrivilegeModel.xml | 3 +++ src/test/resources/realmtest/config/PrivilegeModel.xml | 3 +++ .../transactionalruntime/config/PrivilegeModel.xml | 3 +++ 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java index 0b04337f1..3b04443d7 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java @@ -131,7 +131,7 @@ public class PostgreSqlPersistenceHandler extends StrolchComponent implements Pe @Override public StrolchTransaction openTx(StrolchRealm realm, Certificate certificate, String action) { - return new PostgreSqlStrolchTransaction(realm, certificate, action, this); + return new PostgreSqlStrolchTransaction(getContainer().getPrivilegeHandler(), realm, certificate, action, this); } Connection getConnection(String realm) { diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index d8026176d..1d7a97068 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -24,6 +24,7 @@ import li.strolch.persistence.api.OrderDao; import li.strolch.persistence.api.PersistenceHandler; import li.strolch.persistence.api.ResourceDao; import li.strolch.persistence.api.TransactionResult; +import li.strolch.runtime.privilege.PrivilegeHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,9 +41,9 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { private AuditDao auditDao; private Connection connection; - public PostgreSqlStrolchTransaction(StrolchRealm realm, Certificate certificate, String action, - PostgreSqlPersistenceHandler persistenceHandler) { - super(realm, certificate, action); + public PostgreSqlStrolchTransaction(PrivilegeHandler privilegeHandler, StrolchRealm realm, Certificate certificate, + String action, PostgreSqlPersistenceHandler persistenceHandler) { + super(privilegeHandler, realm, certificate, action); this.persistenceHandler = persistenceHandler; } diff --git a/src/test/resources/cachedruntime/config/PrivilegeModel.xml b/src/test/resources/cachedruntime/config/PrivilegeModel.xml index 14af39def..0ed6ce7b2 100644 --- a/src/test/resources/cachedruntime/config/PrivilegeModel.xml +++ b/src/test/resources/cachedruntime/config/PrivilegeModel.xml @@ -31,6 +31,9 @@ true + + true + \ No newline at end of file diff --git a/src/test/resources/realmtest/config/PrivilegeModel.xml b/src/test/resources/realmtest/config/PrivilegeModel.xml index 14af39def..0ed6ce7b2 100644 --- a/src/test/resources/realmtest/config/PrivilegeModel.xml +++ b/src/test/resources/realmtest/config/PrivilegeModel.xml @@ -31,6 +31,9 @@ true + + true + \ No newline at end of file diff --git a/src/test/resources/transactionalruntime/config/PrivilegeModel.xml b/src/test/resources/transactionalruntime/config/PrivilegeModel.xml index 14af39def..0ed6ce7b2 100644 --- a/src/test/resources/transactionalruntime/config/PrivilegeModel.xml +++ b/src/test/resources/transactionalruntime/config/PrivilegeModel.xml @@ -31,6 +31,9 @@ true + + true + \ No newline at end of file From bba96ef4478330fdfc90cf37340d1fcb6d3e5724 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Sun, 14 Sep 2014 12:20:49 +0200 Subject: [PATCH 60/61] [Minor] code cleanup --- .../postgresql/PostgreSqlAuditDao.java | 2 +- .../PostgreSqlAuditQueryVisitor.java | 28 ++++----- .../PostgreSqlOrderQueryVisitor.java | 8 ++- .../postgresql/PostgreSqlQueryVisitor.java | 60 +++++++++---------- .../PostgreSqlResourceQueryVisitor.java | 2 + .../PostgreSqlStrolchTransaction.java | 2 +- 6 files changed, 53 insertions(+), 49 deletions(-) diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java index c56c7cf1b..ad80954b2 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java @@ -134,7 +134,7 @@ public class PostgreSqlAuditDao implements AuditDao { try (PreparedStatement statement = this.tx.getConnection().prepareStatement(sql)) { try (ResultSet result = statement.executeQuery()) { while (result.next()) { - keySet.add(result.getString(ELEMENT_TYPE)); //$NON-NLS-1$ + keySet.add(result.getString(ELEMENT_TYPE)); } } } catch (SQLException e) { diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java index c43d91d48..379c40407 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java @@ -58,13 +58,13 @@ public class PostgreSqlAuditQueryVisitor implements AuditQueryVisitor { } public String getSql() { - if (sqlAsString != null) - return sqlAsString; + if (this.sqlAsString != null) + return this.sqlAsString; this.sql.append("\nwhere\n"); this.sql.append(this.sb.toString()); - sqlAsString = this.sql.toString(); - return sqlAsString; + this.sqlAsString = this.sql.toString(); + return this.sqlAsString; } @Override @@ -120,21 +120,21 @@ public class PostgreSqlAuditQueryVisitor implements AuditQueryVisitor { ensureAnd(); this.sb.append(this.indent); if (accessTypes.length == 1) { - sb.append(PostgreSqlAuditDao.ACCESS_TYPE + " = ?"); - sb.append(PostgreSqlAuditDao.ACCESS_TYPE_TYPE); - sb.append("\n"); + this.sb.append(PostgreSqlAuditDao.ACCESS_TYPE + " = ?"); + this.sb.append(PostgreSqlAuditDao.ACCESS_TYPE_TYPE); + this.sb.append("\n"); this.values.add(accessTypes[0].name()); } else { - sb.append(PostgreSqlAuditDao.ACCESS_TYPE + " in ("); + this.sb.append(PostgreSqlAuditDao.ACCESS_TYPE + " in ("); for (int i = 0; i < accessTypes.length; i++) { - sb.append("?"); - sb.append(PostgreSqlAuditDao.ACCESS_TYPE_TYPE); - values.add(accessTypes[i].name()); + this.sb.append("?"); + this.sb.append(PostgreSqlAuditDao.ACCESS_TYPE_TYPE); + this.values.add(accessTypes[i].name()); if (i < accessTypes.length - 1) - sb.append(", "); + this.sb.append(", "); } - sb.append(" )\n"); - sb.append("\n"); + this.sb.append(" )\n"); + this.sb.append("\n"); } } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java index 687ac1331..40050292a 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java @@ -32,10 +32,12 @@ public class PostgreSqlOrderQueryVisitor extends PostgreSqlQueryVisitor implemen super(fields); } + @Override protected String getClassName() { return Tags.ORDER; } + @Override protected String getTableName() { return PostgreSqlOrderDao.ORDERS; } @@ -47,8 +49,8 @@ public class PostgreSqlOrderQueryVisitor extends PostgreSqlQueryVisitor implemen @Override public void visit(StateSelection selection) { - sb.append(indent); - sb.append("state = ?::order_state\n"); - values.add(selection.getState().name()); + this.sb.append(this.indent); + this.sb.append("state = ?::order_state\n"); + this.values.add(selection.getState().name()); } } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java index b552746e6..6051c7f53 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java @@ -75,23 +75,23 @@ public abstract class PostgreSqlQueryVisitor implements StrolchRootElementSelect } public String getSql() { - if (sqlAsString != null) - return sqlAsString; + if (this.sqlAsString != null) + return this.sqlAsString; this.sql.append("\nwhere\n"); this.sql.append(this.indent); if (this.any) { this.sql.append("type = ?"); - sqlAsString = this.sql.toString(); - return sqlAsString; + this.sqlAsString = this.sql.toString(); + return this.sqlAsString; } this.sql.append("type = ? and\n"); this.sql.append(this.sb.toString()); - sqlAsString = this.sql.toString(); - return sqlAsString; + this.sqlAsString = this.sql.toString(); + return this.sqlAsString; } /** @@ -235,42 +235,42 @@ public abstract class PostgreSqlQueryVisitor implements StrolchRootElementSelect xpath = xpath.replace("${bagKey}", selection.getBagKey()); xpath = xpath.replace("${paramKey}", selection.getParamKey()); - sb.append(this.indent); - sb.append("id in (\n"); - sb.append(this.indent); - sb.append(" SELECT id\n"); - sb.append(this.indent); - sb.append(" FROM (\n"); - sb.append(this.indent); - sb.append(" SELECT id, UNNEST("); - sb.append(xpath); - sb.append("\n"); - sb.append(this.indent); - sb.append("from "); - sb.append(getTableName()); - sb.append("\n"); - sb.append(this.indent); - sb.append(") AS alias\n"); - sb.append(this.indent); - sb.append("WHERE "); + this.sb.append(this.indent); + this.sb.append("id in (\n"); + this.sb.append(this.indent); + this.sb.append(" SELECT id\n"); + this.sb.append(this.indent); + this.sb.append(" FROM (\n"); + this.sb.append(this.indent); + this.sb.append(" SELECT id, UNNEST("); + this.sb.append(xpath); + this.sb.append("\n"); + this.sb.append(this.indent); + this.sb.append("from "); + this.sb.append(getTableName()); + this.sb.append("\n"); + this.sb.append(this.indent); + this.sb.append(") AS alias\n"); + this.sb.append(this.indent); + this.sb.append("WHERE "); if (selection.getMatchMode().isEquals()) { if (selection.getMatchMode().isCaseSensitve()) { - sb.append("content = ?\n"); + this.sb.append("content = ?\n"); } else { - sb.append("content ILIKE ?\n"); + this.sb.append("content ILIKE ?\n"); } } else { value = "%" + value + "%"; if (selection.getMatchMode().isCaseSensitve()) { - sb.append("content LIKE ?\n"); + this.sb.append("content LIKE ?\n"); } else { - sb.append("content ILIKE ?\n"); + this.sb.append("content ILIKE ?\n"); } } - sb.append(this.indent); - sb.append(")\n"); + this.sb.append(this.indent); + this.sb.append(")\n"); this.values.add(value); } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java index 349641144..4a07fc09f 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java @@ -30,10 +30,12 @@ public class PostgreSqlResourceQueryVisitor extends PostgreSqlQueryVisitor imple super(fields); } + @Override protected String getClassName() { return Tags.RESOURCE; } + @Override protected String getTableName() { return PostgreSqlResourceDao.RESOURCES; } diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java index 1d7a97068..9fa65c181 100644 --- a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java @@ -100,7 +100,7 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction { public AuditDao getAuditDao() { if (this.auditDao == null) this.auditDao = new PostgreSqlAuditDao(this); - return (AuditDao) this.auditDao; + return this.auditDao; } Connection getConnection() { From d101fa84fb416abf4fde4314cd53e8284544a3c7 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 16 Sep 2014 08:52:23 +0200 Subject: [PATCH 61/61] moved everything to a subdirectory for repo merge --- .gitignore => li.strolch.persistence.postgresql/.gitignore | 0 LICENSE => li.strolch.persistence.postgresql/LICENSE | 0 README.md => li.strolch.persistence.postgresql/README.md | 0 pom.xml => li.strolch.persistence.postgresql/pom.xml | 0 .../main/java/li/strolch/persistence/postgresql/DaoCommand.java | 0 .../java/li/strolch/persistence/postgresql/DbConnectionCheck.java | 0 .../li/strolch/persistence/postgresql/DbSchemaVersionCheck.java | 0 .../li/strolch/persistence/postgresql/PostgreSqlAuditDao.java | 0 .../persistence/postgresql/PostgreSqlAuditQueryVisitor.java | 0 .../java/li/strolch/persistence/postgresql/PostgreSqlHelper.java | 0 .../li/strolch/persistence/postgresql/PostgreSqlOrderDao.java | 0 .../persistence/postgresql/PostgreSqlOrderQueryVisitor.java | 0 .../persistence/postgresql/PostgreSqlPersistenceHandler.java | 0 .../li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java | 0 .../li/strolch/persistence/postgresql/PostgreSqlResourceDao.java | 0 .../persistence/postgresql/PostgreSqlResourceQueryVisitor.java | 0 .../persistence/postgresql/PostgreSqlStrolchTransaction.java | 0 .../java/li/strolch/persistence/postgresql/PostgresqlDao.java | 0 .../src}/main/resources/componentVersion.properties | 0 .../src}/main/resources/db_schema_0.1.0_drop.sql | 0 .../src}/main/resources/db_schema_0.1.0_initial.sql | 0 .../src}/main/resources/db_schema_0.2.0_drop.sql | 0 .../src}/main/resources/db_schema_0.2.0_initial.sql | 0 .../src}/main/resources/db_version.properties | 0 .../strolch/persistence/postgresql/dao/test/AuditQueryTest.java | 0 .../li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java | 0 .../persistence/postgresql/dao/test/ObserverUpdateTest.java | 0 .../li/strolch/persistence/postgresql/dao/test/QueryTest.java | 0 .../li/strolch/persistence/postgresql/dao/test/RealmTest.java | 0 .../persistence/postgresql/dao/test/TransactionalDaoTest.java | 0 .../src}/test/resources/cachedruntime/config/PrivilegeConfig.xml | 0 .../src}/test/resources/cachedruntime/config/PrivilegeModel.xml | 0 .../test/resources/cachedruntime/config/StrolchConfiguration.xml | 0 .../src}/test/resources/log4j.xml | 0 .../src}/test/resources/realmtest/config/PrivilegeConfig.xml | 0 .../src}/test/resources/realmtest/config/PrivilegeModel.xml | 0 .../src}/test/resources/realmtest/config/StrolchConfiguration.xml | 0 .../resources/transactionalruntime/config/PrivilegeConfig.xml | 0 .../test/resources/transactionalruntime/config/PrivilegeModel.xml | 0 .../transactionalruntime/config/StrolchConfiguration.xml | 0 40 files changed, 0 insertions(+), 0 deletions(-) rename .gitignore => li.strolch.persistence.postgresql/.gitignore (100%) rename LICENSE => li.strolch.persistence.postgresql/LICENSE (100%) rename README.md => li.strolch.persistence.postgresql/README.md (100%) rename pom.xml => li.strolch.persistence.postgresql/pom.xml (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/DaoCommand.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java (100%) rename {src => li.strolch.persistence.postgresql/src}/main/resources/componentVersion.properties (100%) rename {src => li.strolch.persistence.postgresql/src}/main/resources/db_schema_0.1.0_drop.sql (100%) rename {src => li.strolch.persistence.postgresql/src}/main/resources/db_schema_0.1.0_initial.sql (100%) rename {src => li.strolch.persistence.postgresql/src}/main/resources/db_schema_0.2.0_drop.sql (100%) rename {src => li.strolch.persistence.postgresql/src}/main/resources/db_schema_0.2.0_initial.sql (100%) rename {src => li.strolch.persistence.postgresql/src}/main/resources/db_version.properties (100%) rename {src => li.strolch.persistence.postgresql/src}/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java (100%) rename {src => li.strolch.persistence.postgresql/src}/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java (100%) rename {src => li.strolch.persistence.postgresql/src}/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java (100%) rename {src => li.strolch.persistence.postgresql/src}/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java (100%) rename {src => li.strolch.persistence.postgresql/src}/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java (100%) rename {src => li.strolch.persistence.postgresql/src}/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalDaoTest.java (100%) rename {src => li.strolch.persistence.postgresql/src}/test/resources/cachedruntime/config/PrivilegeConfig.xml (100%) rename {src => li.strolch.persistence.postgresql/src}/test/resources/cachedruntime/config/PrivilegeModel.xml (100%) rename {src => li.strolch.persistence.postgresql/src}/test/resources/cachedruntime/config/StrolchConfiguration.xml (100%) rename {src => li.strolch.persistence.postgresql/src}/test/resources/log4j.xml (100%) rename {src => li.strolch.persistence.postgresql/src}/test/resources/realmtest/config/PrivilegeConfig.xml (100%) rename {src => li.strolch.persistence.postgresql/src}/test/resources/realmtest/config/PrivilegeModel.xml (100%) rename {src => li.strolch.persistence.postgresql/src}/test/resources/realmtest/config/StrolchConfiguration.xml (100%) rename {src => li.strolch.persistence.postgresql/src}/test/resources/transactionalruntime/config/PrivilegeConfig.xml (100%) rename {src => li.strolch.persistence.postgresql/src}/test/resources/transactionalruntime/config/PrivilegeModel.xml (100%) rename {src => li.strolch.persistence.postgresql/src}/test/resources/transactionalruntime/config/StrolchConfiguration.xml (100%) diff --git a/.gitignore b/li.strolch.persistence.postgresql/.gitignore similarity index 100% rename from .gitignore rename to li.strolch.persistence.postgresql/.gitignore diff --git a/LICENSE b/li.strolch.persistence.postgresql/LICENSE similarity index 100% rename from LICENSE rename to li.strolch.persistence.postgresql/LICENSE diff --git a/README.md b/li.strolch.persistence.postgresql/README.md similarity index 100% rename from README.md rename to li.strolch.persistence.postgresql/README.md diff --git a/pom.xml b/li.strolch.persistence.postgresql/pom.xml similarity index 100% rename from pom.xml rename to li.strolch.persistence.postgresql/pom.xml diff --git a/src/main/java/li/strolch/persistence/postgresql/DaoCommand.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/DaoCommand.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/DaoCommand.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/DaoCommand.java diff --git a/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/DbConnectionCheck.java diff --git a/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/DbSchemaVersionCheck.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditDao.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlAuditQueryVisitor.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlHelper.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderDao.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlOrderQueryVisitor.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlPersistenceHandler.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlQueryVisitor.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceDao.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlResourceQueryVisitor.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlStrolchTransaction.java diff --git a/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java similarity index 100% rename from src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java rename to li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java diff --git a/src/main/resources/componentVersion.properties b/li.strolch.persistence.postgresql/src/main/resources/componentVersion.properties similarity index 100% rename from src/main/resources/componentVersion.properties rename to li.strolch.persistence.postgresql/src/main/resources/componentVersion.properties diff --git a/src/main/resources/db_schema_0.1.0_drop.sql b/li.strolch.persistence.postgresql/src/main/resources/db_schema_0.1.0_drop.sql similarity index 100% rename from src/main/resources/db_schema_0.1.0_drop.sql rename to li.strolch.persistence.postgresql/src/main/resources/db_schema_0.1.0_drop.sql diff --git a/src/main/resources/db_schema_0.1.0_initial.sql b/li.strolch.persistence.postgresql/src/main/resources/db_schema_0.1.0_initial.sql similarity index 100% rename from src/main/resources/db_schema_0.1.0_initial.sql rename to li.strolch.persistence.postgresql/src/main/resources/db_schema_0.1.0_initial.sql diff --git a/src/main/resources/db_schema_0.2.0_drop.sql b/li.strolch.persistence.postgresql/src/main/resources/db_schema_0.2.0_drop.sql similarity index 100% rename from src/main/resources/db_schema_0.2.0_drop.sql rename to li.strolch.persistence.postgresql/src/main/resources/db_schema_0.2.0_drop.sql diff --git a/src/main/resources/db_schema_0.2.0_initial.sql b/li.strolch.persistence.postgresql/src/main/resources/db_schema_0.2.0_initial.sql similarity index 100% rename from src/main/resources/db_schema_0.2.0_initial.sql rename to li.strolch.persistence.postgresql/src/main/resources/db_schema_0.2.0_initial.sql diff --git a/src/main/resources/db_version.properties b/li.strolch.persistence.postgresql/src/main/resources/db_version.properties similarity index 100% rename from src/main/resources/db_version.properties rename to li.strolch.persistence.postgresql/src/main/resources/db_version.properties diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java similarity index 100% rename from src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java rename to li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java similarity index 100% rename from src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java rename to li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedDaoTest.java diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java similarity index 100% rename from src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java rename to li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java similarity index 100% rename from src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java rename to li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java similarity index 100% rename from src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java rename to li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java diff --git a/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalDaoTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalDaoTest.java similarity index 100% rename from src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalDaoTest.java rename to li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalDaoTest.java diff --git a/src/test/resources/cachedruntime/config/PrivilegeConfig.xml b/li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/PrivilegeConfig.xml similarity index 100% rename from src/test/resources/cachedruntime/config/PrivilegeConfig.xml rename to li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/PrivilegeConfig.xml diff --git a/src/test/resources/cachedruntime/config/PrivilegeModel.xml b/li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/PrivilegeModel.xml similarity index 100% rename from src/test/resources/cachedruntime/config/PrivilegeModel.xml rename to li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/PrivilegeModel.xml diff --git a/src/test/resources/cachedruntime/config/StrolchConfiguration.xml b/li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/StrolchConfiguration.xml similarity index 100% rename from src/test/resources/cachedruntime/config/StrolchConfiguration.xml rename to li.strolch.persistence.postgresql/src/test/resources/cachedruntime/config/StrolchConfiguration.xml diff --git a/src/test/resources/log4j.xml b/li.strolch.persistence.postgresql/src/test/resources/log4j.xml similarity index 100% rename from src/test/resources/log4j.xml rename to li.strolch.persistence.postgresql/src/test/resources/log4j.xml diff --git a/src/test/resources/realmtest/config/PrivilegeConfig.xml b/li.strolch.persistence.postgresql/src/test/resources/realmtest/config/PrivilegeConfig.xml similarity index 100% rename from src/test/resources/realmtest/config/PrivilegeConfig.xml rename to li.strolch.persistence.postgresql/src/test/resources/realmtest/config/PrivilegeConfig.xml diff --git a/src/test/resources/realmtest/config/PrivilegeModel.xml b/li.strolch.persistence.postgresql/src/test/resources/realmtest/config/PrivilegeModel.xml similarity index 100% rename from src/test/resources/realmtest/config/PrivilegeModel.xml rename to li.strolch.persistence.postgresql/src/test/resources/realmtest/config/PrivilegeModel.xml diff --git a/src/test/resources/realmtest/config/StrolchConfiguration.xml b/li.strolch.persistence.postgresql/src/test/resources/realmtest/config/StrolchConfiguration.xml similarity index 100% rename from src/test/resources/realmtest/config/StrolchConfiguration.xml rename to li.strolch.persistence.postgresql/src/test/resources/realmtest/config/StrolchConfiguration.xml diff --git a/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml similarity index 100% rename from src/test/resources/transactionalruntime/config/PrivilegeConfig.xml rename to li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/PrivilegeConfig.xml diff --git a/src/test/resources/transactionalruntime/config/PrivilegeModel.xml b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/PrivilegeModel.xml similarity index 100% rename from src/test/resources/transactionalruntime/config/PrivilegeModel.xml rename to li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/PrivilegeModel.xml diff --git a/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml similarity index 100% rename from src/test/resources/transactionalruntime/config/StrolchConfiguration.xml rename to li.strolch.persistence.postgresql/src/test/resources/transactionalruntime/config/StrolchConfiguration.xml