Merge branch 'master' of ../postgresql
This commit is contained in:
commit
4f6662f00c
|
@ -0,0 +1,4 @@
|
||||||
|
target/
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.classpath
|
|
@ -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.
|
|
@ -0,0 +1,72 @@
|
||||||
|
li.strolch.persistence.postgresql
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
[![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
|
||||||
|
=======================================================================
|
||||||
|
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 -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:
|
||||||
|
<Component>
|
||||||
|
<name>PersistenceHandler</name>
|
||||||
|
<api>li.strolch.persistence.api.StrolchPersistenceHandler</api>
|
||||||
|
<impl>li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler</impl>
|
||||||
|
<Properties>
|
||||||
|
<allowSchemaCreation>false</allowSchemaCreation>
|
||||||
|
<db.url>jdbc:postgresql://localhost/testdb</db.url>
|
||||||
|
<db.username>testUser</db.username>
|
||||||
|
<db.password>test</db.password>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
|
||||||
|
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
|
|
@ -0,0 +1,102 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>li.strolch</groupId>
|
||||||
|
<artifactId>li.strolch.parent</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../li.strolch.parent/pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>li.strolch.persistence.postgresql</artifactId>
|
||||||
|
|
||||||
|
<name>li.strolch.persistence.postgresql</name>
|
||||||
|
<description>PostgreSQL Persistence Implementation for Strolch</description>
|
||||||
|
|
||||||
|
<url>https://github.com/eitchnet/li.strolch.persistence.postgresql</url>
|
||||||
|
|
||||||
|
<inceptionYear>2011</inceptionYear>
|
||||||
|
|
||||||
|
<issueManagement>
|
||||||
|
<system>Github Issues</system>
|
||||||
|
<url>https://github.com/eitchnet/li.strolch.persistence.postgresql/issues</url>
|
||||||
|
</issueManagement>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<connection>scm:git:https://github.com/eitchnet/li.strolch.persistence.postgresql.git</connection>
|
||||||
|
<developerConnection>scm:git:git@github.com:eitch/li.strolch.persistence.postgresql.git</developerConnection>
|
||||||
|
<url>https://github.com/eitchnet/li.strolch.persistence.postgresql</url>
|
||||||
|
</scm>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- main -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>li.strolch</groupId>
|
||||||
|
<artifactId>li.strolch.model</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>li.strolch</groupId>
|
||||||
|
<artifactId>li.strolch.agent</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>9.3-1100-jdbc41</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- test -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>li.strolch</groupId>
|
||||||
|
<artifactId>li.strolch.testbase</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
<includes>
|
||||||
|
<include>**/componentVersion.properties</include>
|
||||||
|
</includes>
|
||||||
|
</resource>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>false</filtering>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/componentVersion.properties</exclude>
|
||||||
|
</excludes>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-eclipse-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-site-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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.TransactionResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public interface DaoCommand {
|
||||||
|
|
||||||
|
public void doComand(TransactionResult txResult);
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 li.strolch.persistence.api.DbConnectionInfo;
|
||||||
|
import li.strolch.runtime.configuration.StrolchConfigurationException;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class DbConnectionCheck {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DbConnectionCheck.class);
|
||||||
|
private Map<String, DbConnectionInfo> connetionInfoMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param connetionInfoMap
|
||||||
|
*/
|
||||||
|
public DbConnectionCheck(Map<String, DbConnectionInfo> connetionInfoMap) {
|
||||||
|
this.connetionInfoMap = connetionInfoMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkConnections() {
|
||||||
|
Collection<DbConnectionInfo> 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()")) { //$NON-NLS-1$
|
||||||
|
if (rs.next()) {
|
||||||
|
logger.info(MessageFormat.format("Connected to: {0}", rs.getString(1))); //$NON-NLS-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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,205 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
@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<String, DbConnectionInfo> connetionInfoMap;
|
||||||
|
private boolean allowSchemaCreation;
|
||||||
|
private boolean allowSchemaDrop;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param connetionInfoMap
|
||||||
|
* @param componentConfiguration
|
||||||
|
*/
|
||||||
|
public DbSchemaVersionCheck(Map<String, DbConnectionInfo> 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<DbConnectionInfo> 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(MessageFormat.format("[{0}] Checking Schema version for: {1}@{2}", realm, username, url));
|
||||||
|
|
||||||
|
try (Connection con = DriverManager.getConnection(url, username, password);
|
||||||
|
Statement st = con.createStatement();) {
|
||||||
|
|
||||||
|
String expectedDbVersion = getExpectedDbVersion();
|
||||||
|
|
||||||
|
// first see if we have any schema
|
||||||
|
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);
|
||||||
|
} 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)) {
|
||||||
|
String msg = "[{0}] Schema version {1} is the current version. No changes needed.";
|
||||||
|
msg = MessageFormat.format(msg, realm, currentVersion);
|
||||||
|
logger.info(msg);
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getExpectedDbVersion() {
|
||||||
|
Properties dbVersionProps = new Properties();
|
||||||
|
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);
|
||||||
|
} catch (IOException 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}";
|
||||||
|
DBC.PRE.assertNotEmpty(MessageFormat.format(msg, PROP_DB_VERSION, RESOURCE_DB_VERSION), dbVersion);
|
||||||
|
return dbVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSql(String dbVersion, String type) {
|
||||||
|
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);
|
||||||
|
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) {
|
||||||
|
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(MessageFormat.format("[{0}] Creating initial schema...", realm));
|
||||||
|
|
||||||
|
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(MessageFormat.format("[{0}] Successfully created schema for version {1}", realm, dbVersion));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dropSchema(String realm, String dbVersion, Statement st) {
|
||||||
|
|
||||||
|
if (!this.allowSchemaDrop) {
|
||||||
|
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(MessageFormat.format("[{0}] Dropping existing schema...", realm));
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,346 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
import ch.eitchnet.utils.helper.StringHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class PostgreSqlAuditDao implements AuditDao {
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param postgreSqlStrolchTransaction
|
||||||
|
*/
|
||||||
|
public PostgreSqlAuditDao(PostgreSqlStrolchTransaction postgreSqlStrolchTransaction) {
|
||||||
|
this.tx = postgreSqlStrolchTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasElement(String type, Long id) {
|
||||||
|
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);
|
||||||
|
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); //$NON-NLS-1$
|
||||||
|
throw new StrolchPersistenceException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SQLException 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 " + 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());
|
||||||
|
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); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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$
|
||||||
|
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); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> queryTypes() {
|
||||||
|
Set<String> keySet = new HashSet<>();
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
return keySet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Audit queryBy(String type, Long id) {
|
||||||
|
|
||||||
|
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);
|
||||||
|
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); //$NON-NLS-1$
|
||||||
|
return audit;
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Audit> queryAll(String type, DateRange dateRange) {
|
||||||
|
List<Audit> list = new ArrayList<>();
|
||||||
|
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);
|
||||||
|
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); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(Audit audit) {
|
||||||
|
String sql = "insert into " + TABLE_NAME + " (" + FIELDS + ") 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())); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new StrolchPersistenceException(MessageFormat.format("Failed to update Audit {0} due to {1}", audit, //$NON-NLS-1$
|
||||||
|
e.getLocalizedMessage()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveAll(List<Audit> audits) {
|
||||||
|
for (Audit audit : audits) {
|
||||||
|
save(audit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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$
|
||||||
|
try (PreparedStatement preparedStatement = this.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())); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new StrolchPersistenceException(MessageFormat.format("Failed to update Audit {0} due to {1}", audit, //$NON-NLS-1$
|
||||||
|
e.getLocalizedMessage()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateAll(List<Audit> audits) {
|
||||||
|
for (Audit audit : audits) {
|
||||||
|
update(audit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(Audit audit) {
|
||||||
|
String sql = "delete from " + TABLE_NAME + " 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!"; //$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}", //$NON-NLS-1$
|
||||||
|
audit.getId(), e.getLocalizedMessage()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeAll(List<Audit> audits) {
|
||||||
|
for (Audit audit : audits) {
|
||||||
|
remove(audit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long removeAll(String type, DateRange dateRange) {
|
||||||
|
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);
|
||||||
|
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}", //$NON-NLS-1$
|
||||||
|
e.getLocalizedMessage()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <U> List<U> doQuery(AuditQuery query, AuditVisitor<U> auditVisitor) {
|
||||||
|
|
||||||
|
PostgreSqlAuditQueryVisitor queryVisitor = new PostgreSqlAuditQueryVisitor(FIELDS);
|
||||||
|
query.accept(queryVisitor);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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.ElementSelection;
|
||||||
|
import li.strolch.model.audit.IdentitySelection;
|
||||||
|
import li.strolch.model.query.StringSelection;
|
||||||
|
import ch.eitchnet.utils.StringMatchMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class PostgreSqlAuditQueryVisitor implements AuditQueryVisitor {
|
||||||
|
|
||||||
|
protected StringBuilder sql;
|
||||||
|
protected StringBuilder sb;
|
||||||
|
protected List<Object> 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 (this.sqlAsString != null)
|
||||||
|
return this.sqlAsString;
|
||||||
|
|
||||||
|
this.sql.append("\nwhere\n");
|
||||||
|
this.sql.append(this.sb.toString());
|
||||||
|
this.sqlAsString = this.sql.toString();
|
||||||
|
return this.sqlAsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ElementSelection selection) {
|
||||||
|
if (!selection.isElementsAccessedWildcard()) {
|
||||||
|
StringSelection sel = selection.getElementAccessedSelection();
|
||||||
|
toSql(PostgreSqlAuditDao.ELEMENT_ACCESSED, sel.getMatchMode(), sel.getValues());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(IdentitySelection selection) {
|
||||||
|
if (selection.isWildcard())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!selection.isFirstnameWildcard()) {
|
||||||
|
StringSelection sel = selection.getFirstnameSelection();
|
||||||
|
toSql(PostgreSqlAuditDao.FIRSTNAME, sel.getMatchMode(), sel.getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selection.isLastnameWildcard()) {
|
||||||
|
StringSelection sel = selection.getLastnameSelection();
|
||||||
|
toSql(PostgreSqlAuditDao.LASTNAME, sel.getMatchMode(), sel.getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selection.isUsernameWildcard()) {
|
||||||
|
StringSelection sel = selection.getUsernameSelection();
|
||||||
|
toSql(PostgreSqlAuditDao.USERNAME, sel.getMatchMode(), sel.getValues());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ActionSelection selection) {
|
||||||
|
if (!selection.isWildcardAction()) {
|
||||||
|
StringSelection sel = selection.getActionSelection();
|
||||||
|
toSql(PostgreSqlAuditDao.ACTION, sel.getMatchMode(), sel.getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selection.isWildcardActionType()) {
|
||||||
|
|
||||||
|
AccessType[] accessTypes = selection.getAccessTypes();
|
||||||
|
ensureAnd();
|
||||||
|
this.sb.append(this.indent);
|
||||||
|
if (accessTypes.length == 1) {
|
||||||
|
this.sb.append(PostgreSqlAuditDao.ACCESS_TYPE + " = ?");
|
||||||
|
this.sb.append(PostgreSqlAuditDao.ACCESS_TYPE_TYPE);
|
||||||
|
this.sb.append("\n");
|
||||||
|
this.values.add(accessTypes[0].name());
|
||||||
|
} else {
|
||||||
|
this.sb.append(PostgreSqlAuditDao.ACCESS_TYPE + " in (");
|
||||||
|
for (int i = 0; i < accessTypes.length; i++) {
|
||||||
|
this.sb.append("?");
|
||||||
|
this.sb.append(PostgreSqlAuditDao.ACCESS_TYPE_TYPE);
|
||||||
|
this.values.add(accessTypes[i].name());
|
||||||
|
if (i < accessTypes.length - 1)
|
||||||
|
this.sb.append(", ");
|
||||||
|
}
|
||||||
|
this.sb.append(" )\n");
|
||||||
|
this.sb.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ch.eitchnet.utils.StringMatchMode;
|
||||||
|
import ch.eitchnet.utils.collections.DateRange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class PostgreSqlHelper {
|
||||||
|
|
||||||
|
public static void toSql(String indent, StringBuilder sb, List<Object> 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<Object> 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(column + " = ?\n");
|
||||||
|
values.add(query[0]);
|
||||||
|
} else {
|
||||||
|
sb.append(column + " 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(" + column + ") = ?\n");
|
||||||
|
values.add(query[0].toLowerCase());
|
||||||
|
} else {
|
||||||
|
sb.append("lower(" + column + ") 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(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(column + " 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(" + 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(" + column + ") 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<Object> values = new ArrayList<>();
|
||||||
|
String sql = toSql("name", " ", StringMatchMode.CONTAINS_CASE_INSENSITIVE, values, "foo", "bar", "fub");
|
||||||
|
System.out.println(sql);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
sql = toSql("name", " ", StringMatchMode.CONTAINS_CASE_INSENSITIVE, values, "foo");
|
||||||
|
System.out.println(sql);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
sql = toSql("name", " ", StringMatchMode.CONTAINS_CASE_SENSITIVE, values, "foo", "bar", "fub");
|
||||||
|
System.out.println(sql);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
sql = toSql("name", " ", StringMatchMode.CONTAINS_CASE_SENSITIVE, values, "foo");
|
||||||
|
System.out.println(sql);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
sql = toSql("name", " ", StringMatchMode.EQUALS_CASE_INSENSITIVE, values, "foo", "bar", "fub");
|
||||||
|
System.out.println(sql);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
sql = toSql("name", " ", StringMatchMode.EQUALS_CASE_INSENSITIVE, values, "foo");
|
||||||
|
System.out.println(sql);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
sql = toSql("name", " ", StringMatchMode.EQUALS_CASE_SENSITIVE, values, "foo", "bar", "fub");
|
||||||
|
System.out.println(sql);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
sql = toSql("name", " ", StringMatchMode.EQUALS_CASE_SENSITIVE, values, "foo");
|
||||||
|
System.out.println(sql);
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,189 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 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.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;
|
||||||
|
|
||||||
|
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.OrderVisitor;
|
||||||
|
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.XmlModelSaxReader;
|
||||||
|
import li.strolch.persistence.api.OrderDao;
|
||||||
|
import li.strolch.persistence.api.StrolchPersistenceException;
|
||||||
|
|
||||||
|
import org.xml.sax.ContentHandler;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
public class PostgreSqlOrderDao extends PostgresqlDao<Order> implements OrderDao {
|
||||||
|
|
||||||
|
public static final String ORDERS = "orders";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tx
|
||||||
|
*/
|
||||||
|
public PostgreSqlOrderDao(PostgreSqlStrolchTransaction tx) {
|
||||||
|
super(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
} 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 {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SQLException | SAXException e) {
|
||||||
|
throw new StrolchPersistenceException(MessageFormat.format("Failed to update Order {0} due to {1}",
|
||||||
|
order.getLocator(), e.getLocalizedMessage()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <U> List<U> doQuery(OrderQuery query, OrderVisitor<U> orderVisitor) {
|
||||||
|
|
||||||
|
PostgreSqlOrderQueryVisitor queryVisitor = new PostgreSqlOrderQueryVisitor("id, asxml");
|
||||||
|
query.accept(queryVisitor);
|
||||||
|
queryVisitor.validate();
|
||||||
|
|
||||||
|
List<U> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class PostgreSqlOrderQueryVisitor extends PostgreSqlQueryVisitor implements OrderQueryVisitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param fields
|
||||||
|
*/
|
||||||
|
public PostgreSqlOrderQueryVisitor(String fields) {
|
||||||
|
super(fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getClassName() {
|
||||||
|
return Tags.ORDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTableName() {
|
||||||
|
return PostgreSqlOrderDao.ORDERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(DateSelection selection) {
|
||||||
|
PostgreSqlHelper.toSql(this.indent, this.sb, this.values, "date", selection.getDateRange());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(StateSelection selection) {
|
||||||
|
this.sb.append(this.indent);
|
||||||
|
this.sb.append("state = ?::order_state\n");
|
||||||
|
this.values.add(selection.getState().name());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 static ch.eitchnet.utils.helper.StringHelper.DOT;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
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 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;
|
||||||
|
import li.strolch.persistence.api.ResourceDao;
|
||||||
|
import li.strolch.persistence.api.StrolchPersistenceException;
|
||||||
|
import li.strolch.persistence.api.StrolchTransaction;
|
||||||
|
import li.strolch.runtime.StrolchConstants;
|
||||||
|
import li.strolch.runtime.configuration.ComponentConfiguration;
|
||||||
|
import li.strolch.runtime.configuration.StrolchConfigurationException;
|
||||||
|
import ch.eitchnet.privilege.model.Certificate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
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$
|
||||||
|
private static final String PROP_DB_PASSWORD = "db.password"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
private ComponentConfiguration componentConfiguration;
|
||||||
|
private Map<String, DbConnectionInfo> connetionInfoMap;
|
||||||
|
|
||||||
|
public PostgreSqlPersistenceHandler(ComponentContainer container, String componentName) {
|
||||||
|
super(container, componentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(ComponentConfiguration componentConfiguration) {
|
||||||
|
|
||||||
|
this.componentConfiguration = componentConfiguration;
|
||||||
|
this.connetionInfoMap = new HashMap<>();
|
||||||
|
|
||||||
|
Set<String> 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;
|
||||||
|
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(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, connectionInfo.getUrl(), e.getMessage());
|
||||||
|
throw new StrolchConfigurationException(msg, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
String compliant = driver.jdbcCompliant() ? "" : "non"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
|
||||||
|
// test all connections
|
||||||
|
DbConnectionCheck connectionCheck = new DbConnectionCheck(this.connetionInfoMap);
|
||||||
|
connectionCheck.checkConnections();
|
||||||
|
|
||||||
|
DbSchemaVersionCheck schemaVersionCheck = new DbSchemaVersionCheck(this.connetionInfoMap,
|
||||||
|
this.componentConfiguration);
|
||||||
|
schemaVersionCheck.checkSchemaVersion();
|
||||||
|
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StrolchTransaction openTx(StrolchRealm realm, Certificate certificate, String action) {
|
||||||
|
return new PostgreSqlStrolchTransaction(getContainer().getPrivilegeHandler(), realm, certificate, action, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OrderDao getOrderDao(StrolchTransaction tx) {
|
||||||
|
return ((PostgreSqlStrolchTransaction) tx).getOrderDao();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceDao getResourceDao(StrolchTransaction tx) {
|
||||||
|
return ((PostgreSqlStrolchTransaction) tx).getResourceDao();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuditDao getAuditDao(StrolchTransaction tx) {
|
||||||
|
return ((PostgreSqlStrolchTransaction) tx).getAuditDao();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,354 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 static li.strolch.persistence.postgresql.PostgreSqlHelper.toSql;
|
||||||
|
|
||||||
|
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.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.StrolchRootElementSelectionVisitor;
|
||||||
|
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 <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public abstract class PostgreSqlQueryVisitor implements StrolchRootElementSelectionVisitor, ParameterSelectionVisitor {
|
||||||
|
|
||||||
|
protected StringBuilder sql;
|
||||||
|
protected StringBuilder sb;
|
||||||
|
protected String type;
|
||||||
|
protected List<Object> 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 (this.sqlAsString != null)
|
||||||
|
return this.sqlAsString;
|
||||||
|
|
||||||
|
this.sql.append("\nwhere\n");
|
||||||
|
this.sql.append(this.indent);
|
||||||
|
|
||||||
|
if (this.any) {
|
||||||
|
this.sql.append("type = ?");
|
||||||
|
this.sqlAsString = this.sql.toString();
|
||||||
|
return this.sqlAsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sql.append("type = ? and\n");
|
||||||
|
|
||||||
|
this.sql.append(this.sb.toString());
|
||||||
|
this.sqlAsString = this.sql.toString();
|
||||||
|
return this.sqlAsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the any
|
||||||
|
*/
|
||||||
|
public boolean isAny() {
|
||||||
|
return this.any;
|
||||||
|
}
|
||||||
|
|
||||||
|
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<String> 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<String> 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();
|
||||||
|
StringMatchMode mm = selection.getMatchMode();
|
||||||
|
this.sb.append(toSql("name", this.indent, mm, this.values, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitAny() {
|
||||||
|
this.any = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitAnd(AndSelection andSelection) {
|
||||||
|
this.sb.append(this.indent);
|
||||||
|
List<Selection> selections = andSelection.getSelections();
|
||||||
|
this.sb.append("( \n");
|
||||||
|
Iterator<Selection> 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<Selection> selections = orSelection.getSelections();
|
||||||
|
this.sb.append("( \n");
|
||||||
|
Iterator<Selection> 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<Selection> selections = notSelection.getSelections();
|
||||||
|
this.sb.append("not ( \n");
|
||||||
|
Iterator<Selection> 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) {
|
||||||
|
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);
|
||||||
|
this.sb.append(xpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(StringParameterSelection selection) {
|
||||||
|
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());
|
||||||
|
|
||||||
|
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()) {
|
||||||
|
this.sb.append("content = ?\n");
|
||||||
|
} else {
|
||||||
|
this.sb.append("content ILIKE ?\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = "%" + value + "%";
|
||||||
|
if (selection.getMatchMode().isCaseSensitve()) {
|
||||||
|
this.sb.append("content LIKE ?\n");
|
||||||
|
} else {
|
||||||
|
this.sb.append("content ILIKE ?\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sb.append(this.indent);
|
||||||
|
this.sb.append(")\n");
|
||||||
|
|
||||||
|
this.values.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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(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!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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.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;
|
||||||
|
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.ResourceVisitor;
|
||||||
|
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.XmlModelSaxReader;
|
||||||
|
import li.strolch.persistence.api.ResourceDao;
|
||||||
|
import li.strolch.persistence.api.StrolchPersistenceException;
|
||||||
|
|
||||||
|
import org.xml.sax.ContentHandler;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
public class PostgreSqlResourceDao extends PostgresqlDao<Resource> implements ResourceDao {
|
||||||
|
|
||||||
|
public static final String RESOURCES = "resources";
|
||||||
|
|
||||||
|
protected PostgreSqlResourceDao(PostgreSqlStrolchTransaction tx) {
|
||||||
|
super(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
} 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 {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SQLException | SAXException e) {
|
||||||
|
throw new StrolchPersistenceException(MessageFormat.format("Failed to update Resource {0} due to {1}",
|
||||||
|
resource.getLocator(), e.getLocalizedMessage()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <U> List<U> doQuery(ResourceQuery query, ResourceVisitor<U> resourceVisitor) {
|
||||||
|
|
||||||
|
PostgreSqlResourceQueryVisitor queryVisitor = new PostgreSqlResourceQueryVisitor("id, asxml");
|
||||||
|
query.accept(queryVisitor);
|
||||||
|
queryVisitor.validate();
|
||||||
|
|
||||||
|
List<U> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class PostgreSqlResourceQueryVisitor extends PostgreSqlQueryVisitor implements ResourceQueryVisitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param fields
|
||||||
|
*/
|
||||||
|
public PostgreSqlResourceQueryVisitor(String fields) {
|
||||||
|
super(fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getClassName() {
|
||||||
|
return Tags.RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTableName() {
|
||||||
|
return PostgreSqlResourceDao.RESOURCES;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 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;
|
||||||
|
import li.strolch.persistence.api.TransactionResult;
|
||||||
|
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||||
|
|
||||||
|
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);
|
||||||
|
private PostgreSqlPersistenceHandler persistenceHandler;
|
||||||
|
|
||||||
|
private PostgresqlDao<?> orderDao;
|
||||||
|
private PostgresqlDao<?> resourceDao;
|
||||||
|
private AuditDao auditDao;
|
||||||
|
private Connection connection;
|
||||||
|
|
||||||
|
public PostgreSqlStrolchTransaction(PrivilegeHandler privilegeHandler, StrolchRealm realm, Certificate certificate,
|
||||||
|
String action, PostgreSqlPersistenceHandler persistenceHandler) {
|
||||||
|
super(privilegeHandler, realm, certificate, action);
|
||||||
|
this.persistenceHandler = persistenceHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void writeChanges(TransactionResult txResult) throws Exception {
|
||||||
|
|
||||||
|
// first perform DAOs
|
||||||
|
if (this.orderDao != null)
|
||||||
|
this.orderDao.commit(txResult);
|
||||||
|
if (this.resourceDao != null)
|
||||||
|
this.resourceDao.commit(txResult);
|
||||||
|
|
||||||
|
// don't commit the connection, this is done in postCommit when we close the connection
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void rollback(TransactionResult txResult) throws Exception {
|
||||||
|
if (this.connection != null) {
|
||||||
|
try {
|
||||||
|
this.connection.rollback();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
this.connection.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Failed to close connection due to " + e.getMessage(), e); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
return (OrderDao) this.orderDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceDao getResourceDao() {
|
||||||
|
if (this.resourceDao == null)
|
||||||
|
this.resourceDao = new PostgreSqlResourceDao(this);
|
||||||
|
return (ResourceDao) this.resourceDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public AuditDao getAuditDao() {
|
||||||
|
if (this.auditDao == null)
|
||||||
|
this.auditDao = new PostgreSqlAuditDao(this);
|
||||||
|
return this.auditDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection getConnection() {
|
||||||
|
if (this.connection == null) {
|
||||||
|
this.connection = this.persistenceHandler.getConnection(getRealm().getRealm());
|
||||||
|
}
|
||||||
|
return this.connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistenceHandler getPersistenceHandler() {
|
||||||
|
return this.persistenceHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,396 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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.StrolchDao;
|
||||||
|
import li.strolch.persistence.api.StrolchPersistenceException;
|
||||||
|
import li.strolch.persistence.api.TransactionResult;
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
public abstract class PostgresqlDao<T extends StrolchElement> implements StrolchDao<T> {
|
||||||
|
|
||||||
|
protected PostgreSqlStrolchTransaction tx;
|
||||||
|
protected List<DaoCommand> commands;
|
||||||
|
|
||||||
|
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 boolean hasElement(String type, String id) {
|
||||||
|
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);
|
||||||
|
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();
|
||||||
|
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<String> queryKeySet() {
|
||||||
|
|
||||||
|
Set<String> 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<String> queryKeySet(String type) {
|
||||||
|
Set<String> 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<String> queryTypes() {
|
||||||
|
Set<String> 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<T> queryAll() {
|
||||||
|
|
||||||
|
List<T> 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<T> queryAll(String type) {
|
||||||
|
|
||||||
|
List<T> 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(TransactionResult txResult) {
|
||||||
|
internalSave(res);
|
||||||
|
txResult.incCreated(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveAll(final List<T> elements) {
|
||||||
|
this.commands.add(new DaoCommand() {
|
||||||
|
@Override
|
||||||
|
public void doComand(TransactionResult txResult) {
|
||||||
|
for (T element : elements) {
|
||||||
|
internalSave(element);
|
||||||
|
}
|
||||||
|
txResult.incCreated(elements.size());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(final T element) {
|
||||||
|
this.commands.add(new DaoCommand() {
|
||||||
|
@Override
|
||||||
|
public void doComand(TransactionResult txResult) {
|
||||||
|
internalUpdate(element);
|
||||||
|
txResult.incUpdated(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateAll(final List<T> elements) {
|
||||||
|
this.commands.add(new DaoCommand() {
|
||||||
|
@Override
|
||||||
|
public void doComand(TransactionResult txResult) {
|
||||||
|
for (T element : elements) {
|
||||||
|
internalUpdate(element);
|
||||||
|
}
|
||||||
|
txResult.incUpdated(elements.size());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(final T element) {
|
||||||
|
this.commands.add(new DaoCommand() {
|
||||||
|
@Override
|
||||||
|
public void doComand(TransactionResult txResult) {
|
||||||
|
internalRemove(element);
|
||||||
|
txResult.incDeleted(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeAll(final List<T> elements) {
|
||||||
|
this.commands.add(new DaoCommand() {
|
||||||
|
@Override
|
||||||
|
public void doComand(TransactionResult txResult) {
|
||||||
|
for (T element : elements) {
|
||||||
|
internalRemove(element);
|
||||||
|
}
|
||||||
|
txResult.incDeleted(elements.size());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long removeAll() {
|
||||||
|
|
||||||
|
final long toRemove = querySize();
|
||||||
|
|
||||||
|
this.commands.add(new DaoCommand() {
|
||||||
|
@Override
|
||||||
|
public void doComand(TransactionResult txResult) {
|
||||||
|
internalRemoveAll(toRemove);
|
||||||
|
txResult.incDeleted(toRemove);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return toRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long removeAllBy(final String type) {
|
||||||
|
|
||||||
|
final long toRemove = querySize(type);
|
||||||
|
|
||||||
|
this.commands.add(new DaoCommand() {
|
||||||
|
@Override
|
||||||
|
public void doComand(TransactionResult txResult) {
|
||||||
|
internalRemoveAllBy(toRemove, type);
|
||||||
|
txResult.incDeleted(toRemove);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return toRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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());
|
||||||
|
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 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) {
|
||||||
|
for (DaoCommand command : this.commands) {
|
||||||
|
command.doComand(txResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rollback() {
|
||||||
|
this.commands.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
groupId=${project.groupId}
|
||||||
|
artifactId=${project.artifactId}
|
||||||
|
artifactVersion=${project.version}
|
||||||
|
scmRevision=r${buildNumber}
|
||||||
|
scmBranch=${scmBranch}
|
||||||
|
buildTimestamp=${buildTimestamp}
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS resources, orders, db_version;
|
||||||
|
|
||||||
|
DROP TYPE IF EXISTS order_state;
|
||||||
|
|
|
@ -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
|
||||||
|
);
|
|
@ -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;
|
|
@ -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
|
||||||
|
);
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Property file defining what the currently expected version is supposed to be
|
||||||
|
db_version=0.2.0
|
|
@ -0,0 +1,270 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
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.<String> 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.<String> 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<String> expected) throws SQLException {
|
||||||
|
PostgreSqlAuditQueryVisitor visitor = new PostgreSqlAuditQueryVisitor("id");
|
||||||
|
query.accept(visitor);
|
||||||
|
List<String> ids = queryIds(visitor);
|
||||||
|
assertEquals(new HashSet<>(expected), new HashSet<>(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> queryIds(PostgreSqlAuditQueryVisitor visitor) throws SQLException {
|
||||||
|
String sql = visitor.getSql();
|
||||||
|
logger.info("\n" + sql);
|
||||||
|
List<String> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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.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;
|
||||||
|
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 {
|
||||||
|
|
||||||
|
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/cachedruntime"; //$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$
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(CachedDaoTest.class);
|
||||||
|
|
||||||
|
protected static RuntimeMock runtimeMock;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RuntimeMock getRuntimeMock() {
|
||||||
|
return runtimeMock;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClass() {
|
||||||
|
runtimeMock.destroyRuntime();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 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;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import li.strolch.agent.api.Observer;
|
||||||
|
import li.strolch.agent.api.StrolchRealm;
|
||||||
|
import li.strolch.model.Order;
|
||||||
|
import li.strolch.model.Resource;
|
||||||
|
import li.strolch.model.State;
|
||||||
|
import li.strolch.model.StrolchRootElement;
|
||||||
|
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.privilege.PrivilegeHandler;
|
||||||
|
import li.strolch.testbase.runtime.RuntimeMock;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ch.eitchnet.privilege.model.Certificate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class ObserverUpdateTest {
|
||||||
|
|
||||||
|
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/cachedruntime"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
protected static RuntimeMock runtimeMock;
|
||||||
|
|
||||||
|
protected RuntimeMock getRuntimeMock() {
|
||||||
|
return runtimeMock;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClass() {
|
||||||
|
runtimeMock.destroyRuntime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class ElementAddedObserver implements Observer {
|
||||||
|
|
||||||
|
Map<String, ModificationResult> 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<StrolchRootElement> elements) {
|
||||||
|
getModificationResult(key).getUpdated().addAll(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(String key, List<StrolchRootElement> elements) {
|
||||||
|
getModificationResult(key).getDeleted().addAll(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(String key, List<StrolchRootElement> elements) {
|
||||||
|
getModificationResult(key).getCreated().addAll(elements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReceiveUpdates() {
|
||||||
|
|
||||||
|
// register an observer for orders and resources
|
||||||
|
ElementAddedObserver observer = new ElementAddedObserver();
|
||||||
|
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 = 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 = realm.openTx(certificate, "test");) { //$NON-NLS-1$
|
||||||
|
tx.getResourceMap().add(tx, newResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(2, observer.results.size());
|
||||||
|
assertEquals(1, observer.results.get(Tags.ORDER).getCreated().size());
|
||||||
|
assertEquals(1, observer.results.get(Tags.RESOURCE).getCreated().size());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,390 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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.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.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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
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";
|
||||||
|
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("MyType1"));
|
||||||
|
query.withAny();
|
||||||
|
performOrderQuery(query, Arrays.asList("@1", "@2", "@3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldQueryResourceAll() throws SQLException {
|
||||||
|
|
||||||
|
ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType2"));
|
||||||
|
query.withAny();
|
||||||
|
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.<String> asList("@3"));
|
||||||
|
|
||||||
|
// equals earlier
|
||||||
|
query = new OrderQuery(new StrolchTypeNavigation("MyType1"));
|
||||||
|
query.and().with(new DateSelection().from(earlier, false).to(earlier, false));
|
||||||
|
performOrderQuery(query, Arrays.<String> asList("@1"));
|
||||||
|
|
||||||
|
// past
|
||||||
|
query = new OrderQuery(new StrolchTypeNavigation("MyType1"));
|
||||||
|
query.and().with(new DateSelection().to(past, false));
|
||||||
|
performOrderQuery(query, Arrays.<String> asList());
|
||||||
|
|
||||||
|
// future
|
||||||
|
query = new OrderQuery(new StrolchTypeNavigation("MyType1"));
|
||||||
|
query.and().with(new DateSelection().from(future, false));
|
||||||
|
performOrderQuery(query, Arrays.<String> asList());
|
||||||
|
|
||||||
|
// earlier
|
||||||
|
query = new OrderQuery(new StrolchTypeNavigation("MyType1"));
|
||||||
|
query.and().with(new DateSelection().from(past, false).to(earlier, true));
|
||||||
|
performOrderQuery(query, Arrays.<String> asList("@1"));
|
||||||
|
|
||||||
|
// later
|
||||||
|
query = new OrderQuery(new StrolchTypeNavigation("MyType1"));
|
||||||
|
query.and().with(new DateSelection().from(later, false).to(future, true));
|
||||||
|
performOrderQuery(query, Arrays.<String> 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.<String> asList("@2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldQueryOrder1() throws SQLException {
|
||||||
|
|
||||||
|
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("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("@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("@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
|
||||||
|
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("@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("@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("@1", "@2", "@3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldQueryResourceByLongParam() throws SQLException {
|
||||||
|
ResourceQuery query = new ResourceQuery(new StrolchTypeNavigation("MyType2"));
|
||||||
|
query.and().with(ParameterSelection.longSelection("@bag01", "@param4", 4453234566L));
|
||||||
|
performResourceQuery(query, Arrays.asList("@4", "@5", "@6"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldQueryResourceByStringParam() throws SQLException {
|
||||||
|
|
||||||
|
List<String> expected = Arrays.asList("@1", "@2", "@3");
|
||||||
|
|
||||||
|
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.<String> 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("@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.<String> 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.<String> asList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performOrderQuery(OrderQuery query, List<String> expected) throws SQLException {
|
||||||
|
PostgreSqlOrderQueryVisitor visitor = new PostgreSqlOrderQueryVisitor("id");
|
||||||
|
query.accept(visitor);
|
||||||
|
List<String> ids = queryIds(visitor);
|
||||||
|
assertEquals(new HashSet<>(expected), new HashSet<>(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performResourceQuery(ResourceQuery query, List<String> expected) throws SQLException {
|
||||||
|
PostgreSqlResourceQueryVisitor visitor = new PostgreSqlResourceQueryVisitor("id");
|
||||||
|
query.accept(visitor);
|
||||||
|
List<String> ids = queryIds(visitor);
|
||||||
|
assertEquals(new HashSet<>(expected), new HashSet<>(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> queryIds(PostgreSqlQueryVisitor visitor) throws SQLException {
|
||||||
|
String sql = visitor.getSql();
|
||||||
|
logger.info("\n" + sql);
|
||||||
|
List<String> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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.api.StrolchRealm;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
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$
|
||||||
|
|
||||||
|
protected static RuntimeMock runtimeMock;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RuntimeMock getRuntimeMock() {
|
||||||
|
return runtimeMock;
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() throws SQLException {
|
||||||
|
|
||||||
|
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);
|
||||||
|
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"; //$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());
|
||||||
|
|
||||||
|
{
|
||||||
|
StrolchRealm firstRealm = runtimeMock.getRealm(FIRST);
|
||||||
|
assertEquals(DataStoreMode.TRANSACTIONAL, firstRealm.getMode());
|
||||||
|
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)) {
|
||||||
|
Resource res = tx.getResourceMap().getBy(tx, type, expectedId1);
|
||||||
|
assertEquals("Should find object previously added in same realm!", expectedRes1, res); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
StrolchRealm secondRealm = runtimeMock.getRealm(SECOND);
|
||||||
|
assertEquals(DataStoreMode.TRANSACTIONAL, secondRealm.getMode());
|
||||||
|
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)) {
|
||||||
|
Resource res = tx.getResourceMap().getBy(tx, type, expectedId2);
|
||||||
|
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)) {
|
||||||
|
Resource res = tx.getResourceMap().getBy(tx, type, expectedId1);
|
||||||
|
assertNull("Should not find object added in differenct realm!", res); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClass() {
|
||||||
|
runtimeMock.destroyRuntime();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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.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;
|
||||||
|
|
||||||
|
import li.strolch.testbase.runtime.AbstractModelTest;
|
||||||
|
import li.strolch.testbase.runtime.RuntimeMock;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
|
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$
|
||||||
|
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 {
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClass() {
|
||||||
|
runtimeMock.destroyRuntime();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Privilege>
|
||||||
|
|
||||||
|
<Container>
|
||||||
|
|
||||||
|
<Parameters>
|
||||||
|
<!-- parameters for the container itself -->
|
||||||
|
<Parameter name="autoPersistOnPasswordChange" value="true" />
|
||||||
|
</Parameters>
|
||||||
|
|
||||||
|
<EncryptionHandler class="ch.eitchnet.privilege.handler.DefaultEncryptionHandler">
|
||||||
|
<Parameters>
|
||||||
|
<Parameter name="hashAlgorithm" value="SHA-256" />
|
||||||
|
</Parameters>
|
||||||
|
</EncryptionHandler>
|
||||||
|
|
||||||
|
<PersistenceHandler class="ch.eitchnet.privilege.handler.XmlPersistenceHandler">
|
||||||
|
<Parameters>
|
||||||
|
<Parameter name="basePath" value="target/strolchRuntime/config" />
|
||||||
|
<Parameter name="modelXmlFile" value="PrivilegeModel.xml" />
|
||||||
|
</Parameters>
|
||||||
|
</PersistenceHandler>
|
||||||
|
|
||||||
|
</Container>
|
||||||
|
|
||||||
|
<Policies>
|
||||||
|
<Policy name="DefaultPrivilege" class="ch.eitchnet.privilege.policy.DefaultPrivilege" />
|
||||||
|
</Policies>
|
||||||
|
|
||||||
|
</Privilege>
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<UsersAndRoles>
|
||||||
|
|
||||||
|
<Users>
|
||||||
|
<User userId="1" username="agent">
|
||||||
|
<State>SYSTEM</State>
|
||||||
|
<Roles>
|
||||||
|
<Role>agent</Role>
|
||||||
|
</Roles>
|
||||||
|
</User>
|
||||||
|
<User userId="2" username="test" password="9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08">
|
||||||
|
<Firstname>Application</Firstname>
|
||||||
|
<Lastname>Administrator</Lastname>
|
||||||
|
<State>ENABLED</State>
|
||||||
|
<Locale>en_GB</Locale>
|
||||||
|
<Roles>
|
||||||
|
<Role>PrivilegeAdmin</Role>
|
||||||
|
<Role>AppUser</Role>
|
||||||
|
</Roles>
|
||||||
|
</User>
|
||||||
|
</Users>
|
||||||
|
|
||||||
|
<Roles>
|
||||||
|
<Role name="PrivilegeAdmin" />
|
||||||
|
<Role name="agent">
|
||||||
|
<Privilege name="li.strolch.agent.impl.StartRealms" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
</Role>
|
||||||
|
<Role name="AppUser">
|
||||||
|
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
</Role>
|
||||||
|
</Roles>
|
||||||
|
</UsersAndRoles>
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<StrolchConfiguration>
|
||||||
|
<env id="dev">
|
||||||
|
<Runtime>
|
||||||
|
<applicationName>StrolchPersistenceTest</applicationName>
|
||||||
|
<Properties>
|
||||||
|
<verbose>true</verbose>
|
||||||
|
</Properties>
|
||||||
|
</Runtime>
|
||||||
|
<Component>
|
||||||
|
<name>PrivilegeHandler</name>
|
||||||
|
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
|
||||||
|
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
|
||||||
|
<Properties>
|
||||||
|
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component>
|
||||||
|
<name>RealmHandler</name>
|
||||||
|
<api>li.strolch.agent.api.RealmHandler</api>
|
||||||
|
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
|
||||||
|
<depends>PrivilegeHandler</depends>
|
||||||
|
<depends>PersistenceHandler</depends>
|
||||||
|
<Properties>
|
||||||
|
<dataStoreMode>TRANSACTIONAL</dataStoreMode>
|
||||||
|
<enableAuditTrail>true</enableAuditTrail>
|
||||||
|
<enableObserverUpdates>true</enableObserverUpdates>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component>
|
||||||
|
<name>PersistenceHandler</name>
|
||||||
|
<api>li.strolch.persistence.api.PersistenceHandler</api>
|
||||||
|
<impl>li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler</impl>
|
||||||
|
<Properties>
|
||||||
|
<allowSchemaCreation>true</allowSchemaCreation>
|
||||||
|
<allowSchemaDrop>true</allowSchemaDrop>
|
||||||
|
<db.url>jdbc:postgresql://localhost/testdb</db.url>
|
||||||
|
<db.username>testuser</db.username>
|
||||||
|
<db.password>test</db.password>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
</env>
|
||||||
|
</StrolchConfiguration>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE log4j:configuration PUBLIC
|
||||||
|
"-//APACHE//DTD LOG4J 1.2//EN" "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
|
||||||
|
<log4j:configuration debug="false" xmlns:log4j='http://jakarta.apache.org/log4j/'>
|
||||||
|
|
||||||
|
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
|
||||||
|
<layout class="org.apache.log4j.PatternLayout">
|
||||||
|
<param name="ConversionPattern" value="%d %5p [%t] %C{1} %M - %m%n" />
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
<appender name="FILE" class="org.apache.log4j.FileAppender">
|
||||||
|
<param name="File" value="sample.log"/>
|
||||||
|
<param name="BufferedIO" value="true" />
|
||||||
|
<param name="Append" value="true" />
|
||||||
|
<layout class="org.apache.log4j.PatternLayout">
|
||||||
|
<param name="ConversionPattern" value="%d %5p [%t] %C{1} %M - %m%n" />
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="ch.eitchnet">
|
||||||
|
<level value="info" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<root>
|
||||||
|
<priority value="info" />
|
||||||
|
<appender-ref ref="CONSOLE" />
|
||||||
|
<!-- appender-ref ref="FILE" / -->
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</log4j:configuration>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Privilege>
|
||||||
|
|
||||||
|
<Container>
|
||||||
|
|
||||||
|
<Parameters>
|
||||||
|
<!-- parameters for the container itself -->
|
||||||
|
<Parameter name="autoPersistOnPasswordChange" value="true" />
|
||||||
|
</Parameters>
|
||||||
|
|
||||||
|
<EncryptionHandler class="ch.eitchnet.privilege.handler.DefaultEncryptionHandler">
|
||||||
|
<Parameters>
|
||||||
|
<Parameter name="hashAlgorithm" value="SHA-256" />
|
||||||
|
</Parameters>
|
||||||
|
</EncryptionHandler>
|
||||||
|
|
||||||
|
<PersistenceHandler class="ch.eitchnet.privilege.handler.XmlPersistenceHandler">
|
||||||
|
<Parameters>
|
||||||
|
<Parameter name="basePath" value="target/strolchRuntime/config" />
|
||||||
|
<Parameter name="modelXmlFile" value="PrivilegeModel.xml" />
|
||||||
|
</Parameters>
|
||||||
|
</PersistenceHandler>
|
||||||
|
|
||||||
|
</Container>
|
||||||
|
|
||||||
|
<Policies>
|
||||||
|
<Policy name="DefaultPrivilege" class="ch.eitchnet.privilege.policy.DefaultPrivilege" />
|
||||||
|
</Policies>
|
||||||
|
|
||||||
|
</Privilege>
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<UsersAndRoles>
|
||||||
|
|
||||||
|
<Users>
|
||||||
|
<User userId="1" username="agent">
|
||||||
|
<State>SYSTEM</State>
|
||||||
|
<Roles>
|
||||||
|
<Role>agent</Role>
|
||||||
|
</Roles>
|
||||||
|
</User>
|
||||||
|
<User userId="2" username="test" password="9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08">
|
||||||
|
<Firstname>Application</Firstname>
|
||||||
|
<Lastname>Administrator</Lastname>
|
||||||
|
<State>ENABLED</State>
|
||||||
|
<Locale>en_GB</Locale>
|
||||||
|
<Roles>
|
||||||
|
<Role>PrivilegeAdmin</Role>
|
||||||
|
<Role>AppUser</Role>
|
||||||
|
</Roles>
|
||||||
|
</User>
|
||||||
|
</Users>
|
||||||
|
|
||||||
|
<Roles>
|
||||||
|
<Role name="PrivilegeAdmin" />
|
||||||
|
<Role name="agent">
|
||||||
|
<Privilege name="li.strolch.agent.impl.StartRealms" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
</Role>
|
||||||
|
<Role name="AppUser">
|
||||||
|
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
</Role>
|
||||||
|
</Roles>
|
||||||
|
</UsersAndRoles>
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<StrolchConfiguration>
|
||||||
|
<env id="dev">
|
||||||
|
<Runtime>
|
||||||
|
<applicationName>StrolchPersistenceTest</applicationName>
|
||||||
|
<Properties>
|
||||||
|
<verbose>true</verbose>
|
||||||
|
</Properties>
|
||||||
|
</Runtime>
|
||||||
|
<Component>
|
||||||
|
<name>PrivilegeHandler</name>
|
||||||
|
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
|
||||||
|
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
|
||||||
|
<Properties>
|
||||||
|
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component>
|
||||||
|
<name>RealmHandler</name>
|
||||||
|
<api>li.strolch.agent.api.RealmHandler</api>
|
||||||
|
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
|
||||||
|
<depends>PrivilegeHandler</depends>
|
||||||
|
<depends>PersistenceHandler</depends>
|
||||||
|
<Properties>
|
||||||
|
<realms>first, second</realms>
|
||||||
|
<dataStoreMode.first>TRANSACTIONAL</dataStoreMode.first>
|
||||||
|
<dataStoreMode.second>TRANSACTIONAL</dataStoreMode.second>
|
||||||
|
<enableAuditTrail.first>true</enableAuditTrail.first>
|
||||||
|
<enableAuditTrail.second>true</enableAuditTrail.second>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component>
|
||||||
|
<name>PersistenceHandler</name>
|
||||||
|
<api>li.strolch.persistence.api.PersistenceHandler</api>
|
||||||
|
<impl>li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler</impl>
|
||||||
|
<Properties>
|
||||||
|
<allowSchemaCreation>true</allowSchemaCreation>
|
||||||
|
<allowSchemaDrop>true</allowSchemaDrop>
|
||||||
|
|
||||||
|
<db.url.first>jdbc:postgresql://localhost/testdb1</db.url.first>
|
||||||
|
<db.username.first>testuser1</db.username.first>
|
||||||
|
<db.password.first>test</db.password.first>
|
||||||
|
|
||||||
|
<db.url.second>jdbc:postgresql://localhost/testdb2</db.url.second>
|
||||||
|
<db.username.second>testuser2</db.username.second>
|
||||||
|
<db.password.second>test</db.password.second>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
</env>
|
||||||
|
</StrolchConfiguration>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Privilege>
|
||||||
|
|
||||||
|
<Container>
|
||||||
|
|
||||||
|
<Parameters>
|
||||||
|
<!-- parameters for the container itself -->
|
||||||
|
<Parameter name="autoPersistOnPasswordChange" value="true" />
|
||||||
|
</Parameters>
|
||||||
|
|
||||||
|
<EncryptionHandler class="ch.eitchnet.privilege.handler.DefaultEncryptionHandler">
|
||||||
|
<Parameters>
|
||||||
|
<Parameter name="hashAlgorithm" value="SHA-256" />
|
||||||
|
</Parameters>
|
||||||
|
</EncryptionHandler>
|
||||||
|
|
||||||
|
<PersistenceHandler class="ch.eitchnet.privilege.handler.XmlPersistenceHandler">
|
||||||
|
<Parameters>
|
||||||
|
<Parameter name="basePath" value="target/strolchRuntime/config" />
|
||||||
|
<Parameter name="modelXmlFile" value="PrivilegeModel.xml" />
|
||||||
|
</Parameters>
|
||||||
|
</PersistenceHandler>
|
||||||
|
|
||||||
|
</Container>
|
||||||
|
|
||||||
|
<Policies>
|
||||||
|
<Policy name="DefaultPrivilege" class="ch.eitchnet.privilege.policy.DefaultPrivilege" />
|
||||||
|
</Policies>
|
||||||
|
|
||||||
|
</Privilege>
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<UsersAndRoles>
|
||||||
|
|
||||||
|
<Users>
|
||||||
|
<User userId="1" username="agent">
|
||||||
|
<State>SYSTEM</State>
|
||||||
|
<Roles>
|
||||||
|
<Role>agent</Role>
|
||||||
|
</Roles>
|
||||||
|
</User>
|
||||||
|
<User userId="2" username="test" password="9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08">
|
||||||
|
<Firstname>Application</Firstname>
|
||||||
|
<Lastname>Administrator</Lastname>
|
||||||
|
<State>ENABLED</State>
|
||||||
|
<Locale>en_GB</Locale>
|
||||||
|
<Roles>
|
||||||
|
<Role>PrivilegeAdmin</Role>
|
||||||
|
<Role>AppUser</Role>
|
||||||
|
</Roles>
|
||||||
|
</User>
|
||||||
|
</Users>
|
||||||
|
|
||||||
|
<Roles>
|
||||||
|
<Role name="PrivilegeAdmin" />
|
||||||
|
<Role name="agent">
|
||||||
|
<Privilege name="li.strolch.agent.impl.StartRealms" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
</Role>
|
||||||
|
<Role name="AppUser">
|
||||||
|
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
</Role>
|
||||||
|
</Roles>
|
||||||
|
</UsersAndRoles>
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<StrolchConfiguration>
|
||||||
|
<env id="dev">
|
||||||
|
<Runtime>
|
||||||
|
<applicationName>StrolchPersistenceTest</applicationName>
|
||||||
|
<Properties>
|
||||||
|
<verbose>true</verbose>
|
||||||
|
</Properties>
|
||||||
|
</Runtime>
|
||||||
|
<Component>
|
||||||
|
<name>PrivilegeHandler</name>
|
||||||
|
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
|
||||||
|
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
|
||||||
|
<Properties>
|
||||||
|
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component>
|
||||||
|
<name>RealmHandler</name>
|
||||||
|
<api>li.strolch.agent.api.RealmHandler</api>
|
||||||
|
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
|
||||||
|
<depends>PrivilegeHandler</depends>
|
||||||
|
<depends>PersistenceHandler</depends>
|
||||||
|
<Properties>
|
||||||
|
<dataStoreMode>TRANSACTIONAL</dataStoreMode>
|
||||||
|
<enableAuditTrail>true</enableAuditTrail>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component>
|
||||||
|
<name>PersistenceHandler</name>
|
||||||
|
<api>li.strolch.persistence.api.PersistenceHandler</api>
|
||||||
|
<impl>li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler</impl>
|
||||||
|
<Properties>
|
||||||
|
<allowSchemaCreation>true</allowSchemaCreation>
|
||||||
|
<allowSchemaDrop>true</allowSchemaDrop>
|
||||||
|
<db.url>jdbc:postgresql://localhost/testdb</db.url>
|
||||||
|
<db.username>testuser</db.username>
|
||||||
|
<db.password>test</db.password>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
</env>
|
||||||
|
</StrolchConfiguration>
|
Loading…
Reference in New Issue