Merge branch 'master' of ../postgresql

This commit is contained in:
Robert von Burg 2014-09-16 09:03:30 +02:00
commit 4f6662f00c
40 changed files with 4423 additions and 0 deletions

View File

@ -0,0 +1,4 @@
target/
.project
.settings
.classpath

View File

@ -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.

View File

@ -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

View File

@ -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>

View File

@ -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);
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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");
}
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}

View File

@ -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();
}
}

View File

@ -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));
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,6 @@
groupId=${project.groupId}
artifactId=${project.artifactId}
artifactVersion=${project.version}
scmRevision=r${buildNumber}
scmBranch=${scmBranch}
buildTimestamp=${buildTimestamp}

View File

@ -0,0 +1,5 @@
DROP TABLE IF EXISTS resources, orders, db_version;
DROP TYPE IF EXISTS order_state;

View File

@ -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
);

View File

@ -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;

View File

@ -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
);

View File

@ -0,0 +1,2 @@
# Property file defining what the currently expected version is supposed to be
db_version=0.2.0

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>