diff --git a/build.md b/build.md new file mode 100644 index 0000000..8a333c1 --- /dev/null +++ b/build.md @@ -0,0 +1,37 @@ + +# TPQuery Building + +## Requirements + +* java sdk 1.8 or higher. +* maven 3 or higher. + +## Create build artifacts + +cd project-root/; +mvn -Ptpquery-build clean package; + +## Change pom.xml versions + +cd project-root/; +mvn versions:set -DnewVersion=2.3.4-SNAPSHOT + +## Make release build + +cd project-root/; +mvn -Ptpquery-build clean package; +mvn -B -Dusername=(scm_username) clean install release:clean release:prepare release:perform; + +## Make site + +cd project-root/; +mvn -Ptpquery-build-site clean install site:site +Optional add -DstagingDirectory=/tmp/tpquery-build-fullsite +And then manual upload. + +## Check for dependency-updates + +cd project-root/; +mvn versions:display-plugin-updates|grep ">"|uniq; +mvn versions:display-dependency-updates|grep ">"|uniq; + diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..d6111a8 --- /dev/null +++ b/license.txt @@ -0,0 +1,21 @@ +Copyright (c) 2015, Willem Cazander +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided +that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5d7e863 --- /dev/null +++ b/pom.xml @@ -0,0 +1,478 @@ + + 4.0.0 + net.forwardfire.tpquery + tpquery + 0.0.1-SNAPSHOT + pom + tpquery + TemplatedPreparedQuery + 2007 + + ForwardFire.net + http://www.forwardfire.net/ + + + + BSD License + license.txt + repo + BSD 2-Clause License + + + + 3.0.1 + + + tpquery-executor-jdbc + tpquery-executor-jpa + tpquery-store + + + UTF-8 + 1.8 + + + + + org.slf4j + slf4j-api + 1.7.12 + + + org.apache.commons + commons-lang3 + 3.4 + + + junit + junit + 4.12 + + + ch.qos.logback + logback-classic + 1.1.3 + + + com.h2database + h2 + 1.4.187 + + + postgresql + postgresql + 9.1-901-1.jdbc4 + + + org.hibernate + hibernate-entitymanager + 5.0.0.Beta2 + + + org.hibernate + hibernate-validator + 5.2.0.CR1 + + + org.apache.tomcat + tomcat-jasper-el + 8.0.23 + + + javax + javaee-api + 7.0 + + + org.codehaus.sonar-plugins.java + sonar-jacoco-listeners + 3.2 + + + + + + junit + junit + test + + + ch.qos.logback + logback-classic + test + + + com.h2database + h2 + test + + + postgresql + postgresql + test + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + + + maven-compiler-plugin + 3.0 + + ${project.build.sourceEncoding} + ${project.build.sourceVersion} + ${project.build.sourceVersion} + + + + maven-source-plugin + 2.2.1 + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-site-plugin + 3.4 + + + org.apache.maven.doxia + doxia-module-markdown + 1.6 + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 2.8 + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + + org.apache.maven.plugins + maven-pmd-plugin + 3.4 + + + org.codehaus.mojo + findbugs-maven-plugin + 3.0.0 + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.15 + + + org.codehaus.mojo + taglist-maven-plugin + 2.4 + + + org.apache.maven.plugins + maven-surefire-plugin + 2.18.1 + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.18.1 + + + org.jacoco + jacoco-maven-plugin + 0.7.4.201502262128 + + + + + + + + tpquery-test-none + + true + + + + tpquery-test-jacoco + + + + maven-surefire-plugin + + + + listener + org.sonar.java.jacoco.JUnitListener + + + + + + org.jacoco + jacoco-maven-plugin + + + jacoco-prepare-agent + initialize + true + + prepare-agent + + + + + + + + + org.codehaus.sonar-plugins.java + sonar-jacoco-listeners + test + + + + + tpquery-test-jacoco-merge + + + + + org.jacoco + jacoco-maven-plugin + + true + ../target/jacoco.exec + + + ${project.build.directory} + + *.exec + + + + + + + + + + tpquery-build + + + + maven-source-plugin + + + + + + tpquery-build-site + + + + org.apache.maven.plugins + maven-site-plugin + + + org.apache.maven.plugins + maven-project-info-reports-plugin + + + org.apache.maven.shared + maven-shared-jar + 1.1 + + + org.apache.bcel + bcel + + + + + com.google.code.findbugs + bcel-findbugs + 6.0 + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + copy-project-markdown + generate-sources + false + + run + + + + Copy project markdown to site. + + + + + + + + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + + true + false + false + + + + + + dependencies + dependency-convergence + dependency-info + dependency-management + + + + issue-tracking + license + + + plugin-management + plugins + + scm + summary + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + true + true + true + 512m + true + true + + + + + aggregate + + + + + + org.apache.maven.plugins + maven-pmd-plugin + + true + true + ${project.build.sourceEncoding} + 100 + ${project.build.javaVersion} + + + + org.codehaus.mojo + findbugs-maven-plugin + + true + true + true + true + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + true + true + src/config/checkstyle.xml + + + + org.codehaus.mojo + taglist-maven-plugin + + true + + @todo + @deprecated + HELP + TODO + FIXME + LATER + ERROR + SOMETHING + + + + + org.apache.maven.plugins + maven-surefire-report-plugin + + true + + + + + report-only + + + + + + org.jacoco + jacoco-maven-plugin + + true + report + + + + + + + tpquery-sonar + + jdbc:postgres://localhost/ff-sonar + ff-sonar + sonar-ff + http://localhost:9000 + target/surefire-reports + target/jacoco.exec + + + + diff --git a/src/config/checkstyle.xml b/src/config/checkstyle.xml new file mode 100644 index 0000000..3c30a5e --- /dev/null +++ b/src/config/checkstyle.xml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/site/markdown/download.md b/src/site/markdown/download.md new file mode 100644 index 0000000..48722a6 --- /dev/null +++ b/src/site/markdown/download.md @@ -0,0 +1,32 @@ + + +# TPQuery Download + + +## Download location + +Grep the latest release from: [link](http://todo.org/releases/tpquery/) + + + diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md new file mode 100644 index 0000000..c35e8ae --- /dev/null +++ b/src/site/markdown/index.md @@ -0,0 +1,38 @@ + + +# TPQuery Home + +TPQuery is templated prepared statement store. + +## Features + +* Named parameters +* Include query parts +* Default values +* Extra parameter types like LIST and RAW +* QuerySets are nestable. +* Prepared statement cache if possibe. +* Multiple languages supported. +* Validation + diff --git a/src/site/resources/css/site.css b/src/site/resources/css/site.css new file mode 100644 index 0000000..1ce0f07 --- /dev/null +++ b/src/site/resources/css/site.css @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +.breadcrumb,#bannerLeft,#bannerRight,#poweredBy { + display: none +} + diff --git a/src/site/resources/img/logo/tpquery-topbar.png b/src/site/resources/img/logo/tpquery-topbar.png new file mode 100644 index 0000000..7663e44 Binary files /dev/null and b/src/site/resources/img/logo/tpquery-topbar.png differ diff --git a/src/site/site.xml b/src/site/site.xml new file mode 100644 index 0000000..d6e4172 --- /dev/null +++ b/src/site/site.xml @@ -0,0 +1,51 @@ + + + + + org.apache.maven.skins + maven-fluido-skin + 1.3.1 + + + + true + width: 90%; + + TPQuery + ${project.name} + /img/logo/tpquery-topbar.png + /index.html + + false + + false + false + + + + + + + + + + + + + diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..db0ce54 --- /dev/null +++ b/todo.md @@ -0,0 +1,19 @@ +# TPQuery todo + +## Current ERRATA + +* None ? + +## Todo list + +* finish jdoc +* finish site +* rename prepared writers +* Add jmx stats bean + +## Ideas + +* Create eclipse plugin +* add mm auto column. +* add hibernate config plugin + diff --git a/tpquery-executor-jdbc/pom.xml b/tpquery-executor-jdbc/pom.xml new file mode 100644 index 0000000..412e739 --- /dev/null +++ b/tpquery-executor-jdbc/pom.xml @@ -0,0 +1,19 @@ + + 4.0.0 + + net.forwardfire.tpquery + tpquery + 0.0.1-SNAPSHOT + + tpquery-executor-jdbc + tpquery-executor-jdbc + + + ${project.groupId} + tpquery-store + ${project.version} + compile + + + \ No newline at end of file diff --git a/tpquery-executor-jdbc/src/main/java/net/forwardfire/tpquery/store/executor/jdbc/SQLExceptionRuntime.java b/tpquery-executor-jdbc/src/main/java/net/forwardfire/tpquery/store/executor/jdbc/SQLExceptionRuntime.java new file mode 100644 index 0000000..9addb8b --- /dev/null +++ b/tpquery-executor-jdbc/src/main/java/net/forwardfire/tpquery/store/executor/jdbc/SQLExceptionRuntime.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.executor.jdbc; + +import java.sql.SQLException; + +@SuppressWarnings("serial") +public class SQLExceptionRuntime extends RuntimeException { + + public SQLExceptionRuntime(SQLException parent) { + super(parent); + } + + public static SQLExceptionRuntime wrap(SQLException e) { + return new SQLExceptionRuntime(e); + } + + public static SQLExceptionRuntime wrapAndClose(AutoCloseable closeable,SQLException e) { + return close(closeable,wrap(e)); + } + + protected static SQLExceptionRuntime close(AutoCloseable closeable,SQLExceptionRuntime parent) { + try { + closeable.close(); + } catch (Exception ee) { + parent.addSuppressed(ee); + } + return parent; + } +} diff --git a/tpquery-executor-jdbc/src/main/java/net/forwardfire/tpquery/store/executor/jdbc/TPQExecutorJdbc.java b/tpquery-executor-jdbc/src/main/java/net/forwardfire/tpquery/store/executor/jdbc/TPQExecutorJdbc.java new file mode 100644 index 0000000..7a58c37 --- /dev/null +++ b/tpquery-executor-jdbc/src/main/java/net/forwardfire/tpquery/store/executor/jdbc/TPQExecutorJdbc.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.executor.jdbc; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Map; +import java.util.Objects; + +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.store.executor.AbstractTPQExecutor; +import net.forwardfire.tpquery.store.executor.TPQExecutorContext; + +public class TPQExecutorJdbc extends AbstractTPQExecutor { + + public TPQExecutorJdbc(TPQExecutorContext context) { + super(context); + registrateStatementCreator(TPQFactory.StatementLanguage.SQL, (connection,statementText) -> { + try { + return connection.prepareStatement(statementText); + } catch (SQLException e) { + throw SQLExceptionRuntime.wrap(e); + } + }); + } + + public PreparedStatement execute(Connection connection,String queryName) { + return execute(connection, queryName, null); + } + + public PreparedStatement execute(Connection connection,String queryName,Map parameters) { + return execute(createPreparedStatement(connection, queryName, parameters)); + } + + protected PreparedStatement execute(PreparedStatement statement) { + Objects.requireNonNull(statement,"Can't execute with null statement."); + try { + statement.execute(); + return statement; + } catch (SQLException e) { + throw SQLExceptionRuntime.wrapAndClose(statement, e); + } + } + + @Override + protected int executeUpdate(PreparedStatement statement) { + Objects.requireNonNull(statement,"Can't execute update with null statement."); + try { + int result = statement.executeUpdate(); + statement.close(); + return result; + } catch (SQLException e) { + throw SQLExceptionRuntime.wrapAndClose(statement, e); + } + } + + @Override + protected void prepareParameterValue(PreparedStatement statement,int index, Object value) { + try { + statement.setObject(index,value); + } catch (SQLException e) { + throw SQLExceptionRuntime.wrap(e); + } + } + + @Override + protected void prepareTimeout(PreparedStatement statement, Integer timeout) { + try { + statement.setQueryTimeout(timeout); + } catch (SQLException e) { + throw SQLExceptionRuntime.wrap(e); + } + } +} diff --git a/tpquery-executor-jdbc/src/main/java/net/forwardfire/tpquery/store/executor/jdbc/package-info.java b/tpquery-executor-jdbc/src/main/java/net/forwardfire/tpquery/store/executor/jdbc/package-info.java new file mode 100644 index 0000000..8e5aec7 --- /dev/null +++ b/tpquery-executor-jdbc/src/main/java/net/forwardfire/tpquery/store/executor/jdbc/package-info.java @@ -0,0 +1,6 @@ +/** + * Jdbc executor. + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.store.executor.jdbc; diff --git a/tpquery-executor-jdbc/src/test/java/net/forwardfire/tpquery/store/executor/jdbc/TPQExecutorJdbcTest.java b/tpquery-executor-jdbc/src/test/java/net/forwardfire/tpquery/store/executor/jdbc/TPQExecutorJdbcTest.java new file mode 100644 index 0000000..8885f22 --- /dev/null +++ b/tpquery-executor-jdbc/src/test/java/net/forwardfire/tpquery/store/executor/jdbc/TPQExecutorJdbcTest.java @@ -0,0 +1,240 @@ +package net.forwardfire.tpquery.store.executor.jdbc; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.store.executor.jdbc.SQLExceptionRuntime; +import net.forwardfire.tpquery.store.executor.jdbc.TPQExecutorJdbc; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.LoggerContext; + +public class TPQExecutorJdbcTest { + + @BeforeClass + public static void setupLogging() { + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + lc.reset(); // disable logging + } + + @Test() + public void testAutoClose() throws Exception { + SQLExceptionRuntime e = new SQLExceptionRuntime(new SQLException("junit")); + SQLExceptionRuntime.close(new AutoCloseable() { + @Override + public void close() throws Exception { + throw new IllegalArgumentException("test"); + } + }, e); + assertTrue(e.getSuppressed().length>0); + } + + @Test() + public void testExecuteUpdateNull() throws Exception { + try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:test;")) { + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("createTable").appendText("CREATE TABLE test_table (id serial,data int)").build() + .createQuery("insertData").appendText("INSERT INTO test_table (data) VALUES (0)").build() + .createQuery("queryFail") + .parseStatement("update test_table tt set tt.data=$$data$$") + .createQueryParameter("data", Integer.class.getName()) + .setNullable(true) + .build() + .build() + .createQuery("selectData").appendText("SELECT * FROM test_table").build() + .createQuery("selectDataNull") + .parseStatement("SELECT * FROM test_table tt WHERE (tt.data=$$data$$ OR ($$data$$ IS NULL AND tt.data IS NULL))") + .createQueryParameter("data", Integer.class.getName()) + .setNullable(true) + .build() + .build() + .build() + .build(); + + TPQExecutorJdbc exe = new TPQExecutorJdbc(store.getQueryExecutorContext()); + exe.executeUpdate(connection, "junit.createTable"); + exe.executeUpdate(connection, "junit.insertData"); + + printData(exe.execute(connection, "junit.selectData")); + + exe.executeUpdate(connection, "junit.queryFail"); + + printData(exe.execute(connection, "junit.selectData")); + + Map testData = new HashMap<>(); + testData.put("data",null); + + printData(exe.execute(connection, "junit.selectDataNull",testData)); + } + } + + @Test(expected=SQLExceptionRuntime.class) + public void testExecuteUpdateFail() throws Exception { + try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:test;")) { + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("createTable").appendText("CREATE TABLE test_table (id serial,data int)").build() + .createQuery("insertData").appendText("INSERT INTO test_table (data) VALUES (0)").build() + .createQuery("queryFail").appendText("update test_table tt set tt.data=10/(SELECT sum(t1.data) FROM test_table t1)").build() + .build() + .build(); + + TPQExecutorJdbc exe = new TPQExecutorJdbc(store.getQueryExecutorContext()); + exe.executeUpdate(connection, "junit.createTable"); + exe.executeUpdate(connection, "junit.insertData"); + exe.executeUpdate(connection, "junit.queryFail"); // runtime data failure, as prepared will go correctly + } + } + + @Test(expected=SQLExceptionRuntime.class) + public void testExecuteSelectFail() throws Exception { + try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:test;")) { + + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("createTable").appendText("CREATE TABLE test_table (id serial,data int)").build() + .createQuery("insertData").appendText("INSERT INTO test_table (data) VALUES (0)").build() + .createQuery("queryFail").appendText("select tt.* from test_table tt where tt.data=10/(SELECT sum(t1.data) FROM test_table t1)").build() + .build() + .build(); + + TPQExecutorJdbc exe = new TPQExecutorJdbc(store.getQueryExecutorContext()); + exe.executeUpdate(connection, "junit.createTable"); + exe.executeUpdate(connection, "junit.insertData"); + exe.execute(connection, "junit.queryFail"); // runtime data failure, as prepared will go correctly + } + } + + @Test(expected=SQLExceptionRuntime.class) + public void testExecuteSelectFailPrepare() throws Exception { + try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:test;")) { + TPQManager store = TPQFactory.createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem:testcaseFail") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("sql-fail").appendText("select * from article").build() + .build() + .build(); + TPQExecutorJdbc exe = new TPQExecutorJdbc(store.getQueryExecutorContext()); + exe.execute(connection, "junit.sql-fail"); + } + } + + @Test(expected=SQLExceptionRuntime.class) + public void testTimeoutFail() throws Exception { + try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:test;")) { + TPQManager store = TPQFactory.createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem:test") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("createTable").appendText("CREATE TABLE test_table (id serial,data int)").build() + .createQuery("test").appendText("select * from test_table").build() + .build() + .build(); + TPQExecutorJdbc exe = new TPQExecutorJdbc(store.getQueryExecutorContext()); + exe.executeUpdate(connection, "junit.createTable"); + PreparedStatement ps = exe.createPreparedStatement(connection, "junit.test", null); + ps.close(); + exe.prepareTimeout(ps, 123); + } + } + + @Test(expected=SQLExceptionRuntime.class) + public void testParameterFail() throws Exception { + try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:test;")) { + TPQManager store = TPQFactory.createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem:test") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("createTable").appendText("CREATE TABLE test_table (id serial,data int)").build() + .createQuery("test").appendText("select * from test_table").build() + .build() + .build(); + TPQExecutorJdbc exe = new TPQExecutorJdbc(store.getQueryExecutorContext()); + exe.executeUpdate(connection, "junit.createTable"); + PreparedStatement ps = exe.createPreparedStatement(connection, "junit.test", null); + exe.prepareParameterValue(ps, 1, 123); + } + } + + @Test + public void testExecuteBig() throws Exception { + int sizeFactor = 1; + try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:test;")) { + TPQManager queryStore = TPQFactory.createManagerBuilder().readQuerySet("net/forwardfire/tpquery/executor/jdbc/test-big.xml").build(); + TPQExecutorJdbc exe = new TPQExecutorJdbc(queryStore.getQueryExecutorContext()); + //Thread.sleep(1000*5); + + System.out.println("Creating big table..."); + int insertCount = exe.executeUpdate(connection, "TestBig.createTable"); + assertEquals(0,insertCount); + + System.out.println("Creating big test table data..."); + Map testData = new HashMap(); + for (int i=0;i<50*sizeFactor;i++) { + testData.put("id", i); + for (int c=0;c<100;c++) { + String colName = String.format("col%03d", c); + testData.put(colName, ""+i+c); + } + insertCount = exe.executeUpdate(connection, "TestBig.insert",testData); + assertEquals(1,insertCount); + } + + System.out.println("Selecting big test table data..."); + int rows = 0; + testData = new HashMap(); + for (int i=1;i<30*sizeFactor;i++) { + testData.put("col001", ""+1*i); + testData.put("col002", ""+2+i); + testData.put("col003", ""+3/i); + testData.put("col004", ""+4+i); + testData.put("col005", ""+5/i); + testData.put("col006", ""+6*i); + testData.put("col007", ""+7+i); + testData.put("col008", ""+8/i); + testData.put("col009", ""+9*i); + testData.put("col000", ""+0+i); + PreparedStatement ps = exe.execute(connection, "TestBig.getBy10Cols", testData); + //ps.getParameterMetaData(); + ResultSet rs = ps.getResultSet(); + while (rs.next()) { + rows++; + } + } + + System.out.println("Done...rows: "+rows); + } + } + + private void printData(PreparedStatement ps) throws SQLException { + ResultSet rs = ps.getResultSet(); + ps.getParameterMetaData(); + + while (rs.next()) { + System.out.println("data record:"); + for (int i=1;i<=ps.getMetaData().getColumnCount();i++) { + String name = ps.getMetaData().getColumnName(i); + Object value = rs.getObject(i); + System.out.println("column: "+name+" value: "+value); + } + } + } +} diff --git a/tpquery-executor-jdbc/src/test/resources/net/forwardfire/tpquery/executor/jdbc/test-big.xml b/tpquery-executor-jdbc/src/test/resources/net/forwardfire/tpquery/executor/jdbc/test-big.xml new file mode 100644 index 0000000..310d74b --- /dev/null +++ b/tpquery-executor-jdbc/src/test/resources/net/forwardfire/tpquery/executor/jdbc/test-big.xml @@ -0,0 +1,289 @@ + + + + CREATE TABLE test_big ( + id serial, + col000 text,col001 text,col002 text,col003 text,col004 text,col005 text,col006 text,col007 text,col008 text,col009 text, + col010 text,col011 text,col012 text,col013 text,col014 text,col015 text,col016 text,col017 text,col018 text,col019 text, + col020 text,col021 text,col022 text,col023 text,col024 text,col025 text,col026 text,col027 text,col028 text,col029 text, + col030 text,col031 text,col032 text,col033 text,col034 text,col035 text,col036 text,col037 text,col038 text,col039 text, + col040 text,col041 text,col042 text,col043 text,col044 text,col045 text,col046 text,col047 text,col048 text,col049 text, + col050 text,col051 text,col052 text,col053 text,col054 text,col055 text,col056 text,col057 text,col058 text,col059 text, + col060 text,col061 text,col062 text,col063 text,col064 text,col065 text,col066 text,col067 text,col068 text,col069 text, + col070 text,col071 text,col072 text,col073 text,col074 text,col075 text,col076 text,col077 text,col078 text,col079 text, + col080 text,col081 text,col082 text,col083 text,col084 text,col085 text,col086 text,col087 text,col088 text,col089 text, + col090 text,col091 text,col092 text,col093 text,col094 text,col095 text,col096 text,col097 text,col098 text,col099 text + ) + + + + Tests insert parameters as raw + INSERT INTO test_big ($$col_names$$) VALUES ($$col_values$$) + + + + + INSERT INTO test_big ( + id, + $$inc:TestBig.inc.select.col00X$$ , + $$inc:TestBig.inc.select.col01X$$ , + $$inc:TestBig.inc.select.col02X$$ , + $$inc:TestBig.inc.select.col03X$$ , + $$inc:TestBig.inc.select.col04X$$ , + $$inc:TestBig.inc.select.col05X$$ , + $$inc:TestBig.inc.select.col06X$$ , + $$inc:TestBig.inc.select.col07X$$ , + $$inc:TestBig.inc.select.col08X$$ , + $$inc:TestBig.inc.select.col09X$$ + ) VALUES ( + $$id$$ , + $$col000$$ ,$$col001$$ ,$$col002$$ ,$$col003$$ ,$$col004$$ ,$$col005$$ ,$$col006$$ ,$$col007$$ ,$$col008$$ ,$$col009$$ , + $$col010$$ ,$$col011$$ ,$$col012$$ ,$$col013$$ ,$$col014$$ ,$$col015$$ ,$$col016$$ ,$$col017$$ ,$$col018$$ ,$$col019$$ , + $$col020$$ ,$$col021$$ ,$$col022$$ ,$$col023$$ ,$$col024$$ ,$$col025$$ ,$$col026$$ ,$$col027$$ ,$$col028$$ ,$$col029$$ , + $$col030$$ ,$$col031$$ ,$$col032$$ ,$$col033$$ ,$$col034$$ ,$$col035$$ ,$$col036$$ ,$$col037$$ ,$$col038$$ ,$$col039$$ , + $$col040$$ ,$$col041$$ ,$$col042$$ ,$$col043$$ ,$$col044$$ ,$$col045$$ ,$$col046$$ ,$$col047$$ ,$$col048$$ ,$$col049$$ , + $$col050$$ ,$$col051$$ ,$$col052$$ ,$$col053$$ ,$$col054$$ ,$$col055$$ ,$$col056$$ ,$$col057$$ ,$$col058$$ ,$$col059$$ , + $$col060$$ ,$$col061$$ ,$$col062$$ ,$$col063$$ ,$$col064$$ ,$$col065$$ ,$$col066$$ ,$$col067$$ ,$$col068$$ ,$$col069$$ , + $$col070$$ ,$$col071$$ ,$$col072$$ ,$$col073$$ ,$$col074$$ ,$$col075$$ ,$$col076$$ ,$$col077$$ ,$$col078$$ ,$$col079$$ , + $$col080$$ ,$$col081$$ ,$$col082$$ ,$$col083$$ ,$$col084$$ ,$$col085$$ ,$$col086$$ ,$$col087$$ ,$$col088$$ ,$$col089$$ , + $$col090$$ ,$$col091$$ ,$$col092$$ ,$$col093$$ ,$$col094$$ ,$$col095$$ ,$$col096$$ ,$$col097$$ ,$$col098$$ ,$$col099$$ + ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $$inc:TestBig.inc.selectWhere$$ + $$inc:TestBig.inc.orderBy$$ + + + + + $$inc:TestBig.inc.selectWhere$$ + $$inc:TestBig.inc.where.col000$$ + $$inc:TestBig.inc.where.col001$$ + $$inc:TestBig.inc.where.col002$$ + $$inc:TestBig.inc.where.col003$$ + $$inc:TestBig.inc.where.col004$$ + $$inc:TestBig.inc.where.col005$$ + $$inc:TestBig.inc.where.col006$$ + $$inc:TestBig.inc.where.col007$$ + $$inc:TestBig.inc.where.col008$$ + $$inc:TestBig.inc.where.col009$$ + $$inc:TestBig.inc.orderBy$$ + + + + + + col000,col001,col002,col003,col004,col005,col006,col007,col008,col009 + + + col010,col011,col012,col013,col014,col015,col016,col017,col018,col019 + + + col020,col021,col022,col023,col024,col025,col026,col027,col028,col029 + + + col030,col031,col032,col033,col034,col035,col036,col037,col038,col039 + + + col040,col041,col042,col043,col044,col045,col046,col047,col048,col049 + + + col050,col051,col052,col053,col054,col055,col056,col057,col058,col059 + + + col060,col061,col062,col063,col064,col065,col066,col067,col068,col069 + + + col070,col071,col072,col073,col074,col075,col076,col077,col078,col079 + + + col080,col081,col082,col083,col084,col085,col086,col087,col088,col089 + + + col090,col091,col092,col093,col094,col095,col096,col097,col098,col099 + + + + + SELECT + id, + $$inc:TestBig.inc.select.col00X$$ , + $$inc:TestBig.inc.select.col01X$$ , + $$inc:TestBig.inc.select.col02X$$ , + $$inc:TestBig.inc.select.col03X$$ , + $$inc:TestBig.inc.select.col04X$$ , + $$inc:TestBig.inc.select.col05X$$ , + $$inc:TestBig.inc.select.col06X$$ , + $$inc:TestBig.inc.select.col07X$$ , + $$inc:TestBig.inc.select.col08X$$ , + $$inc:TestBig.inc.select.col09X$$ + FROM + test_big + WHERE + true=true + + + + + AND col000 = $$col000$$ + + + + AND col001 = $$col001$$ + + + + AND col002 = $$col002$$ + + + + AND col003 = $$col003$$ + + + + AND col004 = $$col004$$ + + + + AND col005 = $$col005$$ + + + + AND col006 = $$col006$$ + + + + AND col007 = $$col007$$ + + + + AND col008 = $$col008$$ + + + + AND col009 = $$col009$$ + + + + + ORDER BY $$orderColumn$$ $$orderDirection$$ + + + + + + + diff --git a/tpquery-executor-jpa/pom.xml b/tpquery-executor-jpa/pom.xml new file mode 100644 index 0000000..defba77 --- /dev/null +++ b/tpquery-executor-jpa/pom.xml @@ -0,0 +1,39 @@ + + 4.0.0 + + net.forwardfire.tpquery + tpquery + 0.0.1-SNAPSHOT + + tpquery-executor-jpa + + + net.forwardfire.tpquery + tpquery-store + ${project.version} + compile + + + org.hibernate + hibernate-entitymanager + test + + + org.hibernate + hibernate-validator + test + + + org.apache.tomcat + tomcat-jasper-el + test + + + + javax + javaee-api + provided + + + \ No newline at end of file diff --git a/tpquery-executor-jpa/src/main/java/net/forwardfire/tpquery/store/executor/jpa/TPQExecutorJpa.java b/tpquery-executor-jpa/src/main/java/net/forwardfire/tpquery/store/executor/jpa/TPQExecutorJpa.java new file mode 100644 index 0000000..91d48a8 --- /dev/null +++ b/tpquery-executor-jpa/src/main/java/net/forwardfire/tpquery/store/executor/jpa/TPQExecutorJpa.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.executor.jpa; + +import java.util.List; +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.Query; + +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.store.executor.AbstractTPQExecutor; +import net.forwardfire.tpquery.store.executor.TPQExecutorContext; + +public class TPQExecutorJpa extends AbstractTPQExecutor { + + private static final String HINT_TIMEOUT = "javax.persistence.query.timeout"; + + public TPQExecutorJpa(TPQExecutorContext context) { + super(context); + registrateStatementCreator(TPQFactory.StatementLanguage.HQL, (em,stmt) -> em.createQuery(stmt)); + registrateStatementCreator(TPQFactory.StatementLanguage.SQL, (em,stmt) -> em.createNativeQuery(stmt)); + } + + @SuppressWarnings("unchecked") + public List selectList(EntityManager entityManager,String queryName,Map parameters) { + return createPreparedStatement(entityManager, queryName, parameters).getResultList(); + } + + @SuppressWarnings("unchecked") + public E selectObject(EntityManager entityManager,String queryName,Map parameters) { + return (E)createPreparedStatement(entityManager, queryName, parameters).getSingleResult(); + } + + @Override + protected int executeUpdate(Query persistenceQuery) { + return persistenceQuery.executeUpdate(); + } + + @Override + protected void prepareParameterValue(Query persistenceQuery, int index,Object value) { + persistenceQuery.setParameter(index,value); + } + + @Override + protected void prepareTimeout(Query persistenceQuery, Integer timeout) { + persistenceQuery.setHint(HINT_TIMEOUT, timeout); + } +} diff --git a/tpquery-executor-jpa/src/main/java/net/forwardfire/tpquery/store/executor/jpa/package-info.java b/tpquery-executor-jpa/src/main/java/net/forwardfire/tpquery/store/executor/jpa/package-info.java new file mode 100644 index 0000000..f2fa229 --- /dev/null +++ b/tpquery-executor-jpa/src/main/java/net/forwardfire/tpquery/store/executor/jpa/package-info.java @@ -0,0 +1,6 @@ +/** + * Persistance executor. + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.store.executor.jpa; diff --git a/tpquery-executor-jpa/src/test/java/net/forwardfire/tpquery/store/executor/jpa/TPQExecutorJpaTest.java b/tpquery-executor-jpa/src/test/java/net/forwardfire/tpquery/store/executor/jpa/TPQExecutorJpaTest.java new file mode 100644 index 0000000..8e99d26 --- /dev/null +++ b/tpquery-executor-jpa/src/test/java/net/forwardfire/tpquery/store/executor/jpa/TPQExecutorJpaTest.java @@ -0,0 +1,229 @@ +package net.forwardfire.tpquery.store.executor.jpa; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.config.TPQConfig; +import net.forwardfire.tpquery.statement.AbstractTPQStatementWriter; +import net.forwardfire.tpquery.statement.TPQStatementWriter; +import net.forwardfire.tpquery.statement.language.TPQStatementLanguage; +import net.forwardfire.tpquery.store.executor.jpa.TPQExecutorJpa; +import net.forwardfire.tpquery.store.proxy.TPQueryName; +import net.forwardfire.tpquery.store.proxy.TPQueryProxyFactory; +import net.forwardfire.tpquery.store.proxy.TPQueryParameterName; +import net.forwardfire.tpquery.store.proxy.TPQueryProxy; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.LoggerContext; + +public class TPQExecutorJpaTest { + + private EntityManagerFactory emFactory; + private EntityManager em = null; + + @BeforeClass + public static void setupLogging() { + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + lc.reset(); // disable logging + } + + @Before + public void before() { + emFactory = Persistence.createEntityManagerFactory("junit"); + em = emFactory.createEntityManager(); + } + + @After + public void close() { + em.close(); + emFactory.close(); + } + + @Test + public void simple() throws Exception { + + TestEntity t = new TestEntity(); + t.active = true; + t.name = "test"; + t.description = "junit test 012345678901234567890123456789"; + + em.getTransaction().begin(); + em.persist(t); + em.getTransaction().commit(); + + TPQManager store = TPQFactory.createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.HQL) + .createQuery("test-select-sql") + .setLanguage("SQL") + .setTimeout(2000) + .appendText("SELECT * from TestEntity") + .build() + .createQuery("test-select").appendText("from TestEntity").build() + .createQuery("test-select-single") + .appendText("from TestEntity te where te.name=") + .appendParameter("name") + .createQueryParameter("name","text").build() + .build() + .createQuery("test-update") + .appendText("update TestEntity te set te.name=") + .appendParameter("name") + .createQueryParameter("name","text").build() + .build() + .build() + .build(); + + TPQExecutorJpa exe = new TPQExecutorJpa(store.getQueryExecutorContext()); + + //TQueryPrepared p = store.getQueryExecutorContext().prepareQuery("junit.test", null); + //Query q = em.createQuery(p.getStatement()); + //q.getSingleResult(); + //q.getResultList(); + + List resultSql = exe.selectList(em, "junit.test-select-sql", null); + assertNotNull(resultSql); + assertFalse(resultSql.isEmpty()); + + List result = exe.selectList(em, "junit.test-select", null); + assertNotNull(result); + assertFalse(result.isEmpty()); + + Map para = new HashMap<>(); + para.put("name", "foobar"); + em.getTransaction().begin(); + int updateResult = exe.executeUpdate(em, "junit.test-update", para); + em.getTransaction().commit(); + assertEquals(1,updateResult); + + TestEntity resultSingle = exe.selectObject(em, "junit.test-select-single", para); + assertNotNull(resultSingle); + //assertEquals("foobar",resultSingle.name); + } + + @Test(expected=NullPointerException.class) + public void testUnsupportedLanguage() throws Exception { + TPQConfig config = new TPQConfig(); + config.addStatementLanguage(new TPQStatementLanguage() { + @Override + public String getLanguageType() { + return "XQL"; + } + + @Override + public TPQStatementWriter createQueryWriter(Map parameterData) { + return new AbstractTPQStatementWriter(parameterData) { + }; + } + }); + TPQManager store = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .createQuery("test") + .setLanguage("XQL") + .parseStatement("select * from table") + .build() + .build() + .build(); + TPQExecutorJpa exe = new TPQExecutorJpa(store.getQueryExecutorContext()); + exe.selectList(em, "junit.test", null); + } + + @Test() + public void testQueryProxy() throws Exception { + TPQManager store = TPQFactory.createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.HQL) + .createQuery("testSelect").appendText("from TestEntity").build() + .createQuery("testSelectSingle") + .appendText("from TestEntity te where te.name=") + .appendParameter("name") + .createQueryParameter("name","text").build() + .build() + .createQuery("testSelectMultiple") + .appendText("from TestEntity te where te.name=") + .appendParameter("name") + .appendText(" and length(te.name) > ") + .appendParameter("minLength") + .createQueryParameter("name","text").build() + .createQueryParameter("minLength","int").build() + .build() + .createQuery("testUpdate") + .appendText("update TestEntity te set te.name=") + .appendParameter("name") + .createQueryParameter("name","text").build() + .build() + .createQuerySetTree("TestEntityFooBarDataService") + .createQuery("testFoo").appendText("from TestEntity").build() + .buildTree() + .build() + .build(); + TPQExecutorJpa exe = new TPQExecutorJpa(store.getQueryExecutorContext()); + + + TPQueryProxyFactory proxy = new TPQueryProxyFactory(); + proxy.registrateResultHandler(Object.class, (queryName,parameters) -> exe.selectObject (em, queryName, parameters)); + proxy.registrateResultHandler(List.class, (queryName,parameters) -> exe.selectList (em, queryName, parameters)); + proxy.registrateResultHandler(void.class, (queryName,parameters) -> exe.executeUpdate(em, queryName, parameters)); + proxy.registrateResultHandler(int.class, (queryName,parameters) -> exe.executeUpdate(em, queryName, parameters)); + proxy.registrateResultHandler(Integer.class, (queryName,parameters) -> exe.executeUpdate(em, queryName, parameters)); + + TestEntityDataService dataService = proxy.newProxyInstance(TestEntityDataService.class); + TestEntityFooBarDataService foobarService = proxy.newProxyInstance(TestEntityFooBarDataService.class); + + List d = dataService.testSelect(); + assertNotNull(d); + + d = dataService.testSelectMultiple(1,"abc1"); + d = dataService.testSelectMultiple(2,"abc2"); + d = dataService.testSelectMultiple(3,"abc3"); + assertNotNull(d); + + d = foobarService.testFoo(); + assertNotNull(d); + } + + @TPQueryProxy(prefix="junit.") + public interface TestEntityDataService { + + List testSelect(); + + @TPQueryName("testSelectSingle") + TestEntity testSelectSingle( + @TPQueryParameterName("name") + String name + ); + + List testSelectMultiple( + @TPQueryParameterName("minLength") + int length, + @TPQueryParameterName("name") + String name + ); + + void testUpdate(@TPQueryParameterName("name")String name); + } + + @TPQueryProxy(prefix="junit.%s.") + interface TestEntityFooBarDataService { + + @TPQueryName() + List testFoo(); + } +} diff --git a/tpquery-executor-jpa/src/test/java/net/forwardfire/tpquery/store/executor/jpa/TestEntity.java b/tpquery-executor-jpa/src/test/java/net/forwardfire/tpquery/store/executor/jpa/TestEntity.java new file mode 100644 index 0000000..5256c4d --- /dev/null +++ b/tpquery-executor-jpa/src/test/java/net/forwardfire/tpquery/store/executor/jpa/TestEntity.java @@ -0,0 +1,31 @@ +package net.forwardfire.tpquery.store.executor.jpa; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.validation.constraints.NotNull; + +import org.hibernate.validator.constraints.Length; +import org.hibernate.validator.constraints.NotEmpty; + + +@Entity +public class TestEntity { + + @Id + @GeneratedValue + Long id; + + @Column(nullable=false) + @NotNull + Boolean active; + + @NotEmpty + @Column(unique = true) + String name; + + @NotNull + @Length(min = 30, max=200) + String description; +} diff --git a/tpquery-executor-jpa/src/test/resources/META-INF/persistence.xml b/tpquery-executor-jpa/src/test/resources/META-INF/persistence.xml new file mode 100644 index 0000000..e8ef7be --- /dev/null +++ b/tpquery-executor-jpa/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,18 @@ + + + + net.forwardfire.tpquery.store.executor.jpa.TestEntity + + + + + + + + + + + \ No newline at end of file diff --git a/tpquery-store/pom.xml b/tpquery-store/pom.xml new file mode 100644 index 0000000..3d5bb67 --- /dev/null +++ b/tpquery-store/pom.xml @@ -0,0 +1,22 @@ + + 4.0.0 + + net.forwardfire.tpquery + tpquery + 0.0.1-SNAPSHOT + + tpquery-store + + + org.slf4j + slf4j-api + compile + + + org.apache.commons + commons-lang3 + compile + + + \ No newline at end of file diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/TPQFactory.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/TPQFactory.java new file mode 100644 index 0000000..5993dc0 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/TPQFactory.java @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.sql.JDBCType; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +import javax.script.Compilable; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.xml.bind.JAXBException; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.config.TPQConfig; +import net.forwardfire.tpquery.config.TPQConfigInitializer; +import net.forwardfire.tpquery.config.TPQConfigParameterValueHolder; +import net.forwardfire.tpquery.config.TPQConfigParameterValueScripterObjectOrList; +import net.forwardfire.tpquery.config.builder.TPQConfigBuilder; +import net.forwardfire.tpquery.statement.language.TPQStatementLanguageHql; +import net.forwardfire.tpquery.statement.language.TPQStatementLanguageSql; +import net.forwardfire.tpquery.statement.parameter.TPQStatementParameterList; +import net.forwardfire.tpquery.statement.parameter.TPQStatementParameterRaw; +import net.forwardfire.tpquery.statement.parameter.TPQStatementParameterValue; +import net.forwardfire.tpquery.store.TPQueryStoreScriptEngine; +import net.forwardfire.tpquery.store.manager.TPQStoreManager; +import net.forwardfire.tpquery.store.manager.TPQStoreManagerStatementCache; + +/** + * The tpquery factory to create objects. + * + * @author Willem Cazander + * @version 1.0 Jan 14, 2015 + */ +public final class TPQFactory { + + private static final String DEFAULT_TREEPATH_SEPERATOR = "."; + private static final Boolean DEFAULT_PARAMETER_NULLABLE = false; + private static final String DEFAULT_SCRIPT_ENGINE_MINE_TYPE = "text/javascript"; + private static final List DEFAULT_CONFIG_INITIALIZERS = Collections.unmodifiableList(Arrays.asList( + new StatementLanguage(), + new StatementParameter(), + new ParameterValueTypeAlias(), + new ParameterValueFunction(), + new TPQConfigInitializer() { + @Override + public void initializeConfig(TPQConfig config) { + // temp here move to better place. + config.setTreePathSeperator(TPQFactory.DEFAULT_TREEPATH_SEPERATOR); + config.setDefaultParameterNullable(DEFAULT_PARAMETER_NULLABLE); + config.setDefaultParameterType(TPQFactory.StatementParameter.VALUE); + config.setStatementCache(new TPQStoreManagerStatementCache()); + } + } + )); + + protected TPQFactory() { + } + + /** + * Creates a default config. + * @return The config. + */ + public static TPQConfig createConfig() { + return createConfig(DEFAULT_CONFIG_INITIALIZERS); + } + + /** + * Creates a empty config and the inits by the configInit list. + * @param configInit The config initializers. + * @return The config. + */ + public static TPQConfig createConfig(List configInit) { + TPQConfig config = new TPQConfig(); + configInit.forEach(ci -> ci.initializeConfig(config)); + return config; + } + + /** + * Creates a manager from the config. + * @param config The config for the manager. + * @return The manager. + */ + public static TPQManager createManager(TPQConfig config) { + return new TPQStoreManager(config); + } + + // ----- builders + + /** + * Create a builder that returns a manager. + * @return The builder. + * @throws JAXBException If the jaxb marshaller throws an error. + */ + public static TPQConfigBuilder createManagerBuilder() throws JAXBException { + return createManagerBuilder(createConfig()); + } + + /** + * Create a builder that returns a manager. + * @param config The config to build. + * @return The builder. + * @throws JAXBException If the jaxb marshaller throws an error. + */ + public static TPQConfigBuilder createManagerBuilder(TPQConfig config) throws JAXBException { + return new TPQConfigBuilder(config,() -> createManager(config)); + } + + /** + * Create a builder that returns the config. + * @return The builder. + * @throws JAXBException If the jaxb marshaller throws an error. + */ + public static TPQConfigBuilder createConfigBuilder() throws JAXBException { + return createConfigBuilder(createConfig()); + } + + /** + * Create a builder that returns the config. + * @param config The config to build. + * @return The builder. + * @throws JAXBException If the jaxb marshaller throws an error. + */ + public static TPQConfigBuilder createConfigBuilder(TPQConfig config) throws JAXBException { + return new TPQConfigBuilder(config,() -> config); + } + + // ----- classes + + public static final class StatementLanguage implements TPQConfigInitializer { + + public static final String SQL = "SQL"; + public static final String HQL = "HQL"; + + private StatementLanguage() { + } + + @Override + public void initializeConfig(TPQConfig config) { + config.addStatementLanguage(new TPQStatementLanguageSql(SQL)); + config.addStatementLanguage(new TPQStatementLanguageHql(HQL)); + } + } + + public static final class StatementParameter implements TPQConfigInitializer { + public static final String VALUE = "VALUE"; + public static final String LIST = "LIST"; + public static final String RAW = "RAW"; + public static final String RAW_NULL = "RAW_NULL"; + + private StatementParameter() { + } + + @Override + public void initializeConfig(TPQConfig config) { + config.addStatementParameter(new TPQStatementParameterValue(VALUE)); + config.addStatementParameter(new TPQStatementParameterList(LIST)); + config.addStatementParameter(new TPQStatementParameterRaw(RAW,"")); + config.addStatementParameter(new TPQStatementParameterRaw(RAW_NULL,"null")); + } + } + + public static final class ParameterValueType { + // java type + public static final String JAVA_OBJECT = Object.class.getName(); + public static final String BIGDECIMAL = java.math.BigDecimal.class.getName(); + public static final String BOOLEAN = Boolean.class.getName(); + public static final String INTEGER = Integer.class.getName(); + public static final String STRING = String.class.getName(); + public static final String DOUBLE = Double.class.getName(); + public static final String LONG = Long.class.getName(); + public static final String FLOAT = Float.class.getName(); + public static final String SHORT = Short.class.getName(); + public static final String URL = java.net.URL.class.getName(); + public static final String BYTE_DATA = byte[].class.getName(); + + // jdbc types + public static final String SQL_ARRAY = java.sql.Array.class.getName(); + public static final String SQL_BLOB = java.sql.Blob.class.getName(); + public static final String SQL_CLOB = java.sql.Clob.class.getName(); + public static final String SQL_DATE = java.sql.Date.class.getName(); + public static final String SQL_NCLOB = java.sql.NClob.class.getName(); + public static final String SQL_REF = java.sql.Ref.class.getName(); + public static final String SQL_ROWID = java.sql.RowId.class.getName(); + public static final String SQL_STRUCT = java.sql.Struct.class.getName(); + public static final String SQL_XML = java.sql.SQLXML.class.getName(); + public static final String SQL_TIME = java.sql.Time.class.getName(); + public static final String SQL_TIMESTAMP = java.sql.Timestamp.class.getName(); + + protected ParameterValueType() { + } + } + + public static final class ParameterValueTypeAlias implements TPQConfigInitializer { + public static final String NUMERIC = "numeric"; + + public static final String SHORT = "short"; + public static final String INT2 = "int2"; + public static final String SMALLINT = "smallint"; + + public static final String INTEGER = "integer"; + public static final String INT = "int"; + public static final String INT4 = "int4"; + + public static final String LONG = "long"; + public static final String INT8 = "int8"; + public static final String BIGINT = "bigint"; + + public static final String BOOLEAN = "boolean"; + public static final String BOOL = "bool"; + + public static final String FLOAT = "float"; + public static final String FLOAT4 = "float4"; + public static final String REAL = "real"; + + public static final String DOUBLE = "double"; + public static final String FLOAT8 = "float8"; + public static final String DOUBLE_PRECISION = "double precision"; + + public static final String STRING = "string"; + public static final String TEXT = "text"; + public static final String VARCHAR = "varchar"; + public static final String LONGVARCHAR = "longvarchar"; + public static final String CHARACTER_VARYING = "character varying"; + public static final String CHAR = "char"; + public static final String CHARACTER = "character"; + + public static final String DATE = "date"; + public static final String TIME = "time"; + public static final String TIMESTAMP = "timestamp"; + + private ParameterValueTypeAlias() { + } + + @Override + public void initializeConfig(TPQConfig config) { + config.addValueTypeAlias(NUMERIC, ParameterValueType.BIGDECIMAL); + + config.addValueTypeAlias(SHORT, ParameterValueType.SHORT); + config.addValueTypeAlias(INT2, ParameterValueType.SHORT); + config.addValueTypeAlias(SMALLINT, ParameterValueType.SHORT); + + config.addValueTypeAlias(INTEGER, ParameterValueType.INTEGER); + config.addValueTypeAlias(INT, ParameterValueType.INTEGER); + config.addValueTypeAlias(INT4, ParameterValueType.INTEGER); + + config.addValueTypeAlias(LONG, ParameterValueType.LONG); + config.addValueTypeAlias(INT8, ParameterValueType.LONG); + config.addValueTypeAlias(BIGINT, ParameterValueType.LONG); + + config.addValueTypeAlias(BOOLEAN, ParameterValueType.BOOLEAN); + config.addValueTypeAlias(BOOL, ParameterValueType.BOOLEAN); + + config.addValueTypeAlias(FLOAT, ParameterValueType.FLOAT); + config.addValueTypeAlias(FLOAT4, ParameterValueType.FLOAT); + config.addValueTypeAlias(REAL, ParameterValueType.FLOAT); + + config.addValueTypeAlias(DOUBLE, ParameterValueType.DOUBLE); + config.addValueTypeAlias(DOUBLE_PRECISION, ParameterValueType.DOUBLE); + config.addValueTypeAlias(FLOAT8, ParameterValueType.DOUBLE); + + config.addValueTypeAlias(STRING, ParameterValueType.STRING); + config.addValueTypeAlias(TEXT, ParameterValueType.STRING); + config.addValueTypeAlias(VARCHAR, ParameterValueType.STRING); + config.addValueTypeAlias(LONGVARCHAR, ParameterValueType.STRING); + config.addValueTypeAlias(CHARACTER_VARYING, ParameterValueType.STRING); + config.addValueTypeAlias(CHAR, ParameterValueType.STRING); + config.addValueTypeAlias(CHARACTER, ParameterValueType.STRING); + + config.addValueTypeAlias(DATE, ParameterValueType.SQL_DATE); + config.addValueTypeAlias(TIME, ParameterValueType.SQL_TIME); + config.addValueTypeAlias(TIMESTAMP, ParameterValueType.SQL_TIMESTAMP); + + // new jdbc names (missing; DISTINCT and REF_CURSOR) + config.addValueTypeAlias(JDBCType.ARRAY.name(), ParameterValueType.SQL_ARRAY); + config.addValueTypeAlias(JDBCType.BIGINT.name(), ParameterValueType.BIGDECIMAL); + config.addValueTypeAlias(JDBCType.BINARY.name(), ParameterValueType.BYTE_DATA); + config.addValueTypeAlias(JDBCType.BIT.name(), ParameterValueType.BOOLEAN); + config.addValueTypeAlias(JDBCType.BLOB.name(), ParameterValueType.SQL_BLOB); + config.addValueTypeAlias(JDBCType.BOOLEAN.name(), ParameterValueType.BOOLEAN); + config.addValueTypeAlias(JDBCType.CHAR.name(), ParameterValueType.STRING); + config.addValueTypeAlias(JDBCType.CLOB.name(), ParameterValueType.SQL_CLOB); + config.addValueTypeAlias(JDBCType.DATALINK.name(), ParameterValueType.URL); + config.addValueTypeAlias(JDBCType.DATE.name(), ParameterValueType.SQL_DATE); + config.addValueTypeAlias(JDBCType.DECIMAL.name(), ParameterValueType.BIGDECIMAL); + config.addValueTypeAlias(JDBCType.DOUBLE.name(), ParameterValueType.DOUBLE); + config.addValueTypeAlias(JDBCType.FLOAT.name(), ParameterValueType.FLOAT); + config.addValueTypeAlias(JDBCType.INTEGER.name(), ParameterValueType.INTEGER); + config.addValueTypeAlias(JDBCType.JAVA_OBJECT.name(), ParameterValueType.JAVA_OBJECT); + config.addValueTypeAlias(JDBCType.LONGNVARCHAR.name(), ParameterValueType.STRING); + config.addValueTypeAlias(JDBCType.LONGVARBINARY.name(), ParameterValueType.BYTE_DATA); + config.addValueTypeAlias(JDBCType.LONGVARCHAR.name(), ParameterValueType.STRING); + config.addValueTypeAlias(JDBCType.NCHAR.name(), ParameterValueType.STRING); + config.addValueTypeAlias(JDBCType.NCLOB.name(), ParameterValueType.SQL_NCLOB); + config.addValueTypeAlias(JDBCType.NULL.name(), ParameterValueType.JAVA_OBJECT); + config.addValueTypeAlias(JDBCType.NUMERIC.name(), ParameterValueType.BIGDECIMAL); + config.addValueTypeAlias(JDBCType.NVARCHAR.name(), ParameterValueType.STRING); + config.addValueTypeAlias(JDBCType.OTHER.name(), ParameterValueType.JAVA_OBJECT); + config.addValueTypeAlias(JDBCType.REAL.name(), ParameterValueType.FLOAT); + config.addValueTypeAlias(JDBCType.REF.name(), ParameterValueType.SQL_REF); + config.addValueTypeAlias(JDBCType.ROWID.name(), ParameterValueType.SQL_ROWID); + config.addValueTypeAlias(JDBCType.SMALLINT.name(), ParameterValueType.INTEGER); + config.addValueTypeAlias(JDBCType.SQLXML.name(), ParameterValueType.SQL_XML); + config.addValueTypeAlias(JDBCType.STRUCT.name(), ParameterValueType.SQL_STRUCT); + config.addValueTypeAlias(JDBCType.TIME.name(), ParameterValueType.SQL_TIME); + config.addValueTypeAlias(JDBCType.TIME_WITH_TIMEZONE.name(), ParameterValueType.SQL_TIME); + config.addValueTypeAlias(JDBCType.TIMESTAMP.name(), ParameterValueType.SQL_TIMESTAMP); + config.addValueTypeAlias(JDBCType.TIMESTAMP_WITH_TIMEZONE.name(), ParameterValueType.SQL_TIMESTAMP); + config.addValueTypeAlias(JDBCType.TINYINT.name(), ParameterValueType.SHORT); + config.addValueTypeAlias(JDBCType.VARBINARY.name(), ParameterValueType.BYTE_DATA); + config.addValueTypeAlias(JDBCType.VARCHAR.name(), ParameterValueType.STRING); + + } + } + + public static final class ParameterValueFunction implements TPQConfigInitializer { + + private static final String NEW_PREFIX = "new "; + private static final String FUNCTION_PREFIX = "function "; + private static final String FUNCTION_ARGS_BEGIN = "("; + private static final String FUNCTION_ARGS_END = ")"; + private static final String FUNCTION_ARGS_EMPTY = FUNCTION_ARGS_BEGIN+FUNCTION_ARGS_END; + + public static final String CREATE_OBJECT = "createObject"; + public static final String CREATE_ARRAY_LIST = "createArrayList"; + public static final String CREATE_HASH_MAP = "createHashMap"; + public static final String CREATE_OBJECT_LIST = "createObjectList"; + public static final String CREATE_VALUE_HOLDER = "createValueHolder"; + public static final String EPOCH = "epoch"; + public static final String DATE = "date"; + public static final String TIME = "time"; + public static final String TIMESTAMP = "timestamp"; + + private ParameterValueFunction() { + } + + @Override + public void initializeConfig(TPQConfig config) { + + config.addParameterValueScript(FUNCTION_PREFIX + +CREATE_OBJECT+"(clazz,value) {\n" + +"\tif (value) {\n" + +"\t return "+NEW_PREFIX+"clazz(value);\n" + +"\t} else {\n" + +"\t return "+NEW_PREFIX+"clazz();\n" + +"\t}\n" + +"}\n"); + config.addParameterValueScript(FUNCTION_PREFIX + +CREATE_OBJECT_LIST+"(clazz,value) {\n" + +"\tvar values = value.split(',');\n" + +"\tvar result = "+CREATE_ARRAY_LIST+"();\n" + +"\tfor (var i = 0; i < values.length; i++) {\n" + +"\t result.add("+CREATE_OBJECT+"(clazz,values[i]));\n" + +"\t}\n" + +"\treturn result;\n" + +"}\n"); + + config.addParameterValueScript(FUNCTION_PREFIX+CREATE_VALUE_HOLDER+"(value) { return new Packages."+TPQConfigParameterValueHolder.class.getName()+"(value); }"); + + config.addParameterValueScript(buildFunctionCreateObject(CREATE_ARRAY_LIST,ArrayList.class.getName())); + config.addParameterValueScript(buildFunctionCreateObject(CREATE_HASH_MAP,HashMap.class.getName())); + + config.addParameterValueScript(buildFunctionReturn(EPOCH,System.class.getName()+".currentTimeMillis()")); + config.addParameterValueScript(buildFunctionEpochObject(DATE,ParameterValueType.SQL_DATE)); + config.addParameterValueScript(buildFunctionEpochObject(TIME,ParameterValueType.SQL_TIME)); + config.addParameterValueScript(buildFunctionEpochObject(TIMESTAMP,ParameterValueType.SQL_TIMESTAMP)); + + config.setParameterValueEngine(createScriptEngine()); + config.setParameterValueScripter(new TPQConfigParameterValueScripterObjectOrList()); + } + + private TPQueryStoreScriptEngine createScriptEngine() { + ScriptEngine engine = new ScriptEngineManager().getEngineByMimeType(DEFAULT_SCRIPT_ENGINE_MINE_TYPE); + Validate.isInstanceOf(Compilable.class, engine, "ScriptEngine does not implement Compilable interface."); + Validate.isInstanceOf(Invocable.class, engine, "ScriptEngine does not implement Invocable interface."); + return (TPQueryStoreScriptEngine) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{TPQueryStoreScriptEngine.class}, new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + return method.invoke(engine, args); + } + }); + } + + private String buildFunctionReturn(String name,String body) { + return FUNCTION_PREFIX+name+FUNCTION_ARGS_EMPTY+" { return "+body+"; }"; + } + + private String buildFunctionEpochObject(String name,String epochClass) { + return buildFunctionReturn(name,NEW_PREFIX+epochClass+FUNCTION_ARGS_BEGIN+EPOCH+FUNCTION_ARGS_EMPTY+FUNCTION_ARGS_END); + } + + private String buildFunctionCreateObject(String name,String className) { + return buildFunctionReturn(name,CREATE_OBJECT+FUNCTION_ARGS_BEGIN+className+FUNCTION_ARGS_END); + } + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/TPQManager.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/TPQManager.java new file mode 100644 index 0000000..a0e01bc --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/TPQManager.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery; + +import net.forwardfire.tpquery.store.TPQueryStore; +import net.forwardfire.tpquery.store.executor.TPQExecutorContext; + +/** + * The manager holds the query store and executor context. + * + * @author Willem Cazander + * @version 1.0 Feb 14, 2015 + */ +public interface TPQManager { + + /** + * Returns the query store. + * @return The query store. + */ + TPQueryStore getQueryStore(); + + /** + * Returns the query executor context. + * @return The query executor context. + */ + TPQExecutorContext getQueryExecutorContext(); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/AbstractTPQConfig.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/AbstractTPQConfig.java new file mode 100644 index 0000000..8a2e23d --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/AbstractTPQConfig.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.forwardfire.tpquery.config.validate.TPQConfigValidator; +import net.forwardfire.tpquery.model.TPQuerySet; +import net.forwardfire.tpquery.statement.language.TPQStatementLanguage; +import net.forwardfire.tpquery.statement.parameter.TPQStatementParameter; +import net.forwardfire.tpquery.store.TPQueryStoreScriptEngine; +import net.forwardfire.tpquery.store.TPQueryStoreStatementCache; + +/** + * Abstract config data. + * + * @author Willem Cazander + * @version 1.0 May 25, 2015 + */ +public abstract class AbstractTPQConfig { + + protected String treePathSeperator; + protected String defaultParameterType; + protected Boolean defaultParameterNullable; + protected TPQueryStoreStatementCache statementCache; + protected TPQueryStoreScriptEngine parameterValueEngine; + protected TPQConfigParameterValueScripter parameterValueScripter; + protected final Map querySets; + protected final Map statementParameters; + protected final Map statementLanguages; + protected final Map valueTypeAliases; + protected final List configValidators; + protected final List parameterValueScripts; + + protected AbstractTPQConfig() { + this(new HashMap<>(),new HashMap<>(),new HashMap<>(),new HashMap<>(),new ArrayList<>(),new ArrayList<>()); + } + + protected AbstractTPQConfig( + Map querySets, + Map statementParameters, + Map statementLanguages, + Map valueTypeAliases, + List configValidators, + List parameterValueScripts + ) { + this.querySets=querySets; + this.statementParameters=statementParameters; + this.statementLanguages=statementLanguages; + this.valueTypeAliases=valueTypeAliases; + this.configValidators=configValidators; + this.parameterValueScripts=parameterValueScripts; + } + + /** + * @return the treePathSeperator + */ + public String getTreePathSeperator() { + return treePathSeperator; + } + + /** + * @return the defaultParameterType + */ + public String getDefaultParameterType() { + return defaultParameterType; + } + + /** + * @return the defaultParameterNullable + */ + public Boolean getDefaultParameterNullable() { + return defaultParameterNullable; + } + + /** + * @return the statementCache + */ + public TPQueryStoreStatementCache getStatementCache() { + return statementCache; + } + + /** + * @return the parameterValueEngine + */ + public TPQueryStoreScriptEngine getParameterValueEngine() { + return parameterValueEngine; + } + + /** + * @return the parameterValueScripter + */ + public TPQConfigParameterValueScripter getParameterValueScripter() { + return parameterValueScripter; + } + + /** + * @return the querySets + */ + public Map getQuerySets() { + return querySets; + } + + /** + * @return the statementParameters + */ + public Map getStatementParameters() { + return statementParameters; + } + + /** + * @return the statementLanguages + */ + public Map getStatementLanguages() { + return statementLanguages; + } + + /** + * @return the valueTypeAliases + */ + public Map getValueTypeAliases() { + return valueTypeAliases; + } + + /** + * @return the configValidators + */ + public List getConfigValidators() { + return configValidators; + } + + /** + * @return the parameterValueScripts + */ + public List getParameterValueScripts() { + return parameterValueScripts; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfig.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfig.java new file mode 100644 index 0000000..01077d8 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfig.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config; + +import java.util.Map; + +import java.util.Objects; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.config.validate.TPQConfigValidator; +import net.forwardfire.tpquery.config.validate.TPQConfigValidatorCheck; +import net.forwardfire.tpquery.model.TPQuerySet; +import net.forwardfire.tpquery.statement.language.TPQStatementLanguage; +import net.forwardfire.tpquery.statement.parameter.TPQStatementParameter; +import net.forwardfire.tpquery.store.TPQueryStoreScriptEngine; +import net.forwardfire.tpquery.store.TPQueryStoreStatementCache; + +/** + * Holds the config to build the query manager. + * + * @author Willem Cazander + * @version 1.0 May 17, 2015 + */ +public class TPQConfig extends AbstractTPQConfig { + + /** + * Creates a empty TPQStore. + */ + public TPQConfig() { + super(); + } + + /** + * @param treePathSeperator the treePathSeperator to set. + */ + public void setTreePathSeperator(String treePathSeperator) { + this.treePathSeperator = Validate.notNull(treePathSeperator,"Can't set treePathSeperator to null"); + } + + /** + * @param defaultParameterType the defaultParameterType to set + */ + public void setDefaultParameterType(String defaultParameterType) { + this.defaultParameterType = Validate.notNull(defaultParameterType,"Can't set defaultParameterType to null"); + } + + /** + * @param defaultParameterNullable the defaultParameterNullable to set + */ + public void setDefaultParameterNullable(Boolean defaultParameterNullable) { + this.defaultParameterNullable = Validate.notNull(defaultParameterNullable,"Can't set defaultParameterNullable to null"); + } + + /** + * @param statementCache the statementCache to set + */ + public void setStatementCache(TPQueryStoreStatementCache statementCache) { + this.statementCache = Validate.notNull(statementCache,"Can't set statementCache to null"); + } + + /** + * @param parameterValueScripter the parameterValueScripter to set + */ + public void setParameterValueScripter(TPQConfigParameterValueScripter parameterValueScripter) { + this.parameterValueScripter = Validate.notNull(parameterValueScripter,"Can't set parameterValueScripter to null"); + } + + /** + * @param parameterValueEngine the parameterValueEngine to set + */ + public void setParameterValueEngine(TPQueryStoreScriptEngine parameterValueEngine) { + this.parameterValueEngine = Validate.notNull(parameterValueEngine,"Can't set parameterValueEngine to null"); + } + + private void mapAdd(Map map,K key,V value) { + Validate.notNull(map); + Validate.notNull(key); + Validate.notNull(value); + Validate.isTrue(Objects.isNull(map.get(key)),"Cannot handle key twice: %s",key); + map.put(key, value); + } + + private void mapRemove(Map map,K key) { + Validate.notNull(Validate.notNull(map).remove(Validate.notNull(key)),"No object for key %s",key); + } + + /** + * Adds a query set. + * @param qs The query set to add. + * @param systemId The systemId from which the query set was loaded. + */ + public void addQuerySet(String systemId,TPQuerySet qs) { + mapAdd(querySets, systemId, qs); + } + + /** + * Removes a query set. + * @param systemId The systemId of the query set to remove. + */ + public void removeQuerySet(String systemId) { + mapRemove(querySets,systemId); + } + + /** + * Adds a statement parameter. + * @param statementParameter The statement parameter to add. + */ + public void addStatementParameter(TPQStatementParameter statementParameter) { + mapAdd(statementParameters, statementParameter.getParameterType(), statementParameter); + } + + /** + * Removes a statement parameter. + * @param statementParameterKey The parameter key. + */ + public void removeStatementParameter(String statementParameterKey) { + mapRemove(statementParameters,statementParameterKey); + } + + /** + * Adds a statement language. + * @param statementLanguage The statement language to add. + */ + public void addStatementLanguage(TPQStatementLanguage statementLanguage) { + mapAdd(statementLanguages, statementLanguage.getLanguageType(), statementLanguage); + } + + /** + * Removes a statement language. + * @param statementLanguageKey The statement language key. + */ + public void removeStatementLanguage(String statementLanguageKey) { + mapRemove(statementLanguages, statementLanguageKey); + } + + /** + * Adds a value alias. + * @param alias The alias to add. + * @param valueType The aliases valueType. + */ + public void addValueTypeAlias(String alias,String valueType) { + mapAdd(valueTypeAliases, alias, valueType); + } + + /** + * Remove a value type alias. + * @param alias The alias to remove. + */ + public void removeValueTypeAlias(String alias) { + mapRemove(valueTypeAliases, alias); + } + + /** + * Adds a config validator. + * @param namePattern The pattern where to check. + * @param validatorChecker The checker validator. + * @return The validator. + */ + public TPQConfigValidator addConfigValidator(String namePattern,TPQConfigValidatorCheck validatorChecker) { + TPQConfigValidator result = new TPQConfigValidator(namePattern,validatorChecker); // validator does null check + configValidators.add(result); + return result; + } + + /** + * Removes a config validator. + * @param validator The validator to remove. + */ + public void removeConfigValidator(TPQConfigValidator validator) { + configValidators.remove(Validate.notNull(validator,"Can't remove null validator")); + } + + /** + * Adds a value script. + * @param script The script to add. + */ + public void addParameterValueScript(String script) { + parameterValueScripts.add(Validate.notNull(script,"Can't add null script.")); + } + + /** + * Removes a value script. + * @param script The script to remove. + */ + public void removeParameterValueScript(String script) { + parameterValueScripts.remove(Validate.notNull(script,"Can't remove null script.")); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfigInitializer.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfigInitializer.java new file mode 100644 index 0000000..04af7e2 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfigInitializer.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config; + +/** + * Interface to split the config init over classes. + * + * @author Willem Cazander + * @version 1.0 Jun 1, 2015 + */ +public interface TPQConfigInitializer { + + /** + * init config. + * @param config The config to init. + */ + void initializeConfig(TPQConfig config); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfigParameterValueHolder.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfigParameterValueHolder.java new file mode 100644 index 0000000..5329ce8 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfigParameterValueHolder.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config; + +/** + * Caches a default value as a value so it only need to be resolved once. + * + * @author Willem Cazander + * @version 1.0 May 28, 2015 + */ +public final class TPQConfigParameterValueHolder { + + private final Object value; + + /** + * Creates this value holder. + * @param value The value to hold. + */ + public TPQConfigParameterValueHolder(Object value) { + this.value=value; + } + + /** + * Returns the constant value. + * @return The value. + */ + public Object getValue() { + return value; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfigParameterValueScripter.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfigParameterValueScripter.java new file mode 100644 index 0000000..04f5e8d --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfigParameterValueScripter.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config; + +import net.forwardfire.tpquery.model.TPQueryParameter; + +/** + * Convert a default value to a script to resolve the value as object. + * + * @author Willem Cazander + * @version 1.0 May 26, 2015 + */ +public interface TPQConfigParameterValueScripter { + + /** + * Convert the defaultValue to script form. + * @param queryParameter The query parameter to create de script for. + * @return The text of the script. + */ + String convertDefaultValueToScript(TPQueryParameter queryParameter); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfigParameterValueScripterObjectOrList.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfigParameterValueScripterObjectOrList.java new file mode 100644 index 0000000..db5ab12 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/TPQConfigParameterValueScripterObjectOrList.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config; + +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.model.TPQueryParameter; + +/** + * Can convert objects and list to a js script value. + * + * @author Willem Cazander + * @version 1.0 May 27, 2015 + */ +public class TPQConfigParameterValueScripterObjectOrList implements TPQConfigParameterValueScripter { + + protected static final String PREFIX_JS = "js:"; + + @Override + public String convertDefaultValueToScript(TPQueryParameter queryParameter) { + String defaultValue = queryParameter.getDefaultValue(); + if (defaultValue.startsWith(PREFIX_JS)) { + return defaultValue.substring(PREFIX_JS.length()); + } else { + return createDefaultValueToScript(queryParameter); + } + } + + private String createDefaultValueToScript(TPQueryParameter queryParameter) { + // Create object function wrappers + String functionName = TPQFactory.ParameterValueFunction.CREATE_OBJECT; + if (TPQFactory.StatementParameter.LIST.equals(queryParameter.getType())) { + functionName = TPQFactory.ParameterValueFunction.CREATE_OBJECT_LIST; + } + String value = queryParameter.getDefaultValue().replaceAll("'", "\\\\'"); + String function = functionName+"("+queryParameter.getValueType()+",'"+value+"')"; + + // Wrap in value holder because these values will not change anymore. + return PREFIX_JS+TPQFactory.ParameterValueFunction.CREATE_VALUE_HOLDER+"("+function+");"; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/AbstractTPQBuilder.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/AbstractTPQBuilder.java new file mode 100644 index 0000000..c522c5d --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/AbstractTPQBuilder.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.builder; + +import java.util.function.Consumer; + +/** + * Abstract object builder with parent builder. + * + * + * @param

The parent builder. + * @param The object to build. + * @param This builder. + * @author Willem Cazander + * @version 1.0 May 29, 2015 + */ +public abstract class AbstractTPQBuilder { + + private final P parent; + private final T value; + + /** + * Creates the builder. + * @param parent The parent builder. + * @param value The object to build. + */ + public AbstractTPQBuilder(P parent,T value) { + this.parent=parent; + this.value=value; + } + + protected P getParent() { + return parent; + } + + protected T getValue() { + return value; + } + + protected abstract B getBuilder(); + + /** + * Builds the result. + * @return The result. + */ + public final P build() { + buildParent(); + return getParent(); + } + + protected abstract void buildParent(); + + protected B make(Consumer mixer) { + mixer.accept(getValue()); + return getBuilder(); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/AbstractTPQueryNodeBuilder.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/AbstractTPQueryNodeBuilder.java new file mode 100644 index 0000000..7d4e364 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/AbstractTPQueryNodeBuilder.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.builder; + +import net.forwardfire.tpquery.model.AbstractTPQueryNode; +import net.forwardfire.tpquery.model.TPQueryHint; + +/** + * Abstract query node builder for the shared properties of the AbstractTPQueryNode. + * + * @author Willem Cazander + * @version 1.0 May 29, 2015 + */ +public abstract class AbstractTPQueryNodeBuilder extends AbstractTPQBuilder { + + public AbstractTPQueryNodeBuilder(P parent, T build) { + super(parent, build); + } + + /** + * Sets the language. + * @param language The langauge. + * @return The builder. + */ + public B setLanguage(String language) { + return make(build -> build.setLanguage(language)); + } + + /** + * Sets the description. + * @param description The description. + * @return The builder; + */ + public B setDescription(String description) { + return make(build -> build.setDescription(description)); + } + + /** + * Sets the template option. + * @param template The template option. + * @return The builder. + */ + public B setTemplate(Boolean template) { + return make(build -> build.setTemplate(template)); + } + + /** + * Sets the timeout. + * @param timeout The timeout. + * @return The builder. + */ + public B setTimeout(Integer timeout) { + return make(build -> build.setTimeout(timeout)); + } + + /** + * Adds an query hint. + * @param name The name. + * @param value The value. + * @return The builder. + */ + public B addQueryHint(String name,String value) { + return make(build -> build.addQueryHint(new TPQueryHint(name,value))); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQConfigBuilder.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQConfigBuilder.java new file mode 100644 index 0000000..efef2c5 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQConfigBuilder.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.builder; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.Objects; +import java.util.function.Supplier; + +import javax.xml.bind.JAXBException; + +import net.forwardfire.tpquery.config.TPQConfig; +import net.forwardfire.tpquery.model.TPQuerySet; +import net.forwardfire.tpquery.model.TPQuerySetXMLMarshaller; +import net.forwardfire.tpquery.statement.TPQStatementMarshaller; + +/** + * The root config builder. + * + * @author Willem Cazander + * @version 1.0 May 22, 2015 + */ +public class TPQConfigBuilder { + + private final TPQConfig storeConfig; + private final Supplier resultBuilder; + private final TPQuerySetXMLMarshaller xmlDriver; + private final TPQStatementMarshaller statementMarshaller; + + /** + * Creates a config builder. + * @param storeConfig The config to build. + * @param resultBuilder the result of this builder. + * @throws JAXBException If the jaxb marshaller throws an error. + */ + public TPQConfigBuilder(TPQConfig storeConfig,Supplier resultBuilder) throws JAXBException { + Objects.requireNonNull(storeConfig,"Can't build null config."); + Objects.requireNonNull(resultBuilder,"Can't build with null builder."); + this.storeConfig = storeConfig; + this.resultBuilder = resultBuilder; + this.xmlDriver = new TPQuerySetXMLMarshaller(); + this.statementMarshaller = new TPQStatementMarshaller(); + } + + protected TPQStatementMarshaller getStatementMarshaller() { + return statementMarshaller; + } + + /** + * Build the result. + * @return The result. + */ + public T build() { + return resultBuilder.get(); + } + + /** + * Adds an query set. + * @param systemId The systemId of the query set. + * @param querySet The query set to add. + * @return The builder. + */ + public TPQConfigBuilder addQuerySet(String systemId,TPQuerySet querySet) { + storeConfig.addQuerySet(systemId,querySet); + return this; + } + + protected TPQConfigBuilder readQuerySet(InputStream input,String systemId) throws JAXBException { + Objects.requireNonNull(input, "Can't read null InputStream"); + return addQuerySet(systemId,xmlDriver.unmarshal(input)); + } + + /** + * Reads an query set. + * @param resource The resource to read. + * @return The builder. + * @throws JAXBException When marshall error. + */ + public TPQConfigBuilder readQuerySet(String resource) throws JAXBException { + Objects.requireNonNull(resource, "Can't read null resource"); + return readQuerySet(getClass().getClassLoader().getResourceAsStream(resource),resource); + } + + /** + * Reads an query set. + * @param file The file to read. + * @return The builder. + * @throws JAXBException When marshall error. + */ + public TPQConfigBuilder readQuerySet(File file) throws JAXBException { + Objects.requireNonNull(file, "Can't read null File"); + try { + return readQuerySet(new FileInputStream(file),file.getAbsolutePath()); + } catch (FileNotFoundException e) { + throw new JAXBException(e); + } + } + + /** + * Creates an query set. + * @param name The query set name. + * @param systemId The query set systemId. + * @return The builder. + */ + public TPQuerySetBuilder createQuerySet(String name,String systemId) { + return new TPQuerySetBuilder(this,name,systemId); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQueryBuilder.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQueryBuilder.java new file mode 100644 index 0000000..7bf9489 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQueryBuilder.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.builder; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.statement.TPQStatement; +import net.forwardfire.tpquery.statement.TPQStatementPartInclude; +import net.forwardfire.tpquery.statement.TPQStatementPartParameter; +import net.forwardfire.tpquery.statement.TPQStatementPartText; + +/** + * Builds queries. + * + * @author Willem Cazander + * @version 1.0 May 29, 2015 + */ +public class TPQueryBuilder extends AbstractTPQueryNodeBuilder> { + + private final TPQConfigBuilder configBuilder; + private final TPQueryBuilderParent builderParent; + + /** + * Creates the query builder. + * @param configBuilder The parent config builder. + * @param parent The parent builder. + * @param name The name of the query. + * @param builderParent The callback to build the parent. + */ + public TPQueryBuilder(TPQConfigBuilder configBuilder,P parent,String name,TPQueryBuilderParent builderParent) { + super(parent,new TPQuery(name)); + this.configBuilder = configBuilder; + this.builderParent = builderParent; + } + + @Override + protected TPQueryBuilder getBuilder() { + return this; + } + + @Override + protected void buildParent() { + builderParent.buildChild(getValue()); + } + + // ------- + + /** + * Create a query parameter. + * @param name The parameter name. + * @param valueType The parameter value type. + * @return The builder. + */ + public TPQueryParameterBuilder createQueryParameter(String name,String valueType) { + return new TPQueryParameterBuilder(this,name,valueType); + } + + /** + * Create a query parameter. + * @param name The parameter name. + * @param valueTypeClass The parameter value type. + * @return The builder. + */ + public TPQueryParameterBuilder createQueryParameter(String name,Class valueTypeClass) { + Validate.notNull(valueTypeClass, "Can't append null valueTypeClass"); + return createQueryParameter(name, valueTypeClass.getName()); + } + + /** + * Addes an query part. + * @param queryPart The part to add. + * @return The builder. + */ + public TPQueryBuilder addQueryPart(TPQStatement queryPart) { + Validate.notNull(queryPart, "Can't append null queryPart"); + getValue().addQueryPart(queryPart); + return this; + } + + /** + * Parsed the statement into parts. + * @param value The statement value. + * @return The builder. + */ + public TPQueryBuilder parseStatement(String value) { + Validate.notNull(value, "Can't parse null value"); + getValue().getQueryParts().addAll(configBuilder.getStatementMarshaller().unmarshal(value)); + return this; + } + + /** + * Appends text part. + * @param value The part value. + * @return The builder. + */ + public TPQueryBuilder appendText(String value) { + return addQueryPart(new TPQStatementPartText(Validate.notNull(value, "Can't append null textvalue"))); + } + + /** + * Appends parameter part. + * @param value The part value. + * @return The builder. + */ + public TPQueryBuilder appendParameter(String value) { + return addQueryPart(new TPQStatementPartParameter(Validate.notNull(value, "Can't append null template value"))); + } + + /** + * Appends include part. + * @param value The part value. + * @return The builder. + */ + public TPQueryBuilder appendInclude(String value) { + return addQueryPart(new TPQStatementPartInclude(Validate.notNull(value, "Can't append null include value"))); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQueryBuilderParent.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQueryBuilderParent.java new file mode 100644 index 0000000..bc6d977 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQueryBuilderParent.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.builder; + +import net.forwardfire.tpquery.model.TPQuery; + +/** + * Build the parent for when we don't know the parent. + * + * @author Willem Cazander + * @version 1.0 May 29, 2015 + */ +public interface TPQueryBuilderParent { + + /** + * Build the query child to the parent. + * @param query The child query. + */ + void buildChild(TPQuery query); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQueryParameterBuilder.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQueryParameterBuilder.java new file mode 100644 index 0000000..2645c8f --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQueryParameterBuilder.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.builder; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQueryParameter; + +/** + * Builds query parameters. + * + * @author Willem Cazander + * @version 1.0 May 29, 2015 + */ +public class TPQueryParameterBuilder extends AbstractTPQBuilder,TPQueryParameter,TPQueryParameterBuilder> { + + public TPQueryParameterBuilder(TPQueryBuilder parent,String name,String valueType) { + super(parent,new TPQueryParameter(name,valueType)); + } + + @Override + protected TPQueryParameterBuilder getBuilder() { + return this; + } + + @Override + protected void buildParent() { + getParent().getValue().addQueryParameter(getValue()); + } + + // ------- + + /** + * Sets the parameter type. + * @param type The type to set. + * @return The builder. + */ + public TPQueryParameterBuilder setType(String type) { + return make(build -> build.setType(Validate.notNull(type, "Can't set null type"))); + } + + /** + * Sets the parameter default value. + * @param defaultValue The defaultValue to set. + * @return The builder. + */ + public TPQueryParameterBuilder setDefaultValue(String defaultValue) { + return make(build -> build.setDefaultValue(Validate.notNull(defaultValue, "Can't set null default value"))); + } + + /** + * Sets the parameter nullable. + * @param nullable The nullable to set. + * @return The builder. + */ + public TPQueryParameterBuilder setNullable(Boolean nullable) { + return make(build -> build.setNullable(Validate.notNull(nullable, "Can't set null nullable"))); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQuerySetBuilder.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQuerySetBuilder.java new file mode 100644 index 0000000..1c6c1a6 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQuerySetBuilder.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.builder; + +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQuerySet; + +/** + * Builds query set. + * + * @author Willem Cazander + * @version 1.0 May 29, 2015 + */ +public class TPQuerySetBuilder extends AbstractTPQueryNodeBuilder,TPQuerySet,TPQuerySetBuilder> { + + private final String systemId; + + /** + * Creates an query set builder. + * @param parent The parent builder. + * @param name The name of the query set. + * @param systemId The systemId of the query set. + */ + public TPQuerySetBuilder(TPQConfigBuilder parent,String name,String systemId) { + super(parent,new TPQuerySet(name)); + this.systemId=systemId; + } + + @Override + protected TPQuerySetBuilder getBuilder() { + return this; + } + + @Override + protected void buildParent() { + getParent().addQuerySet(systemId, getValue()); + } + + // ------- + + /** + * Create a query. + * @param name The query name. + * @return The builder. + */ + public TPQueryBuilder> createQuery(String name) { + return new TPQueryBuilder>(getParent(),this,name,new TPQueryBuilderParent() { + @Override + public void buildChild(TPQuery query) { + getValue().addQuery(query); + } + }); + } + + /** + * Adds a query set. + * @param qs The query set to add. + * @return The builder. + */ + public TPQuerySetBuilder addQuerySet(TPQuerySet qs) { + return make(build -> build.addQuerySet(qs)); + } + + /** + * Create a query set tree. + * @param name The query set name. + * @return The tree builder. + */ + public TPQuerySetNodeBuilder createQuerySetTree(String name) { + return new TPQuerySetNodeBuilder(this,null,name); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQuerySetNodeBuilder.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQuerySetNodeBuilder.java new file mode 100644 index 0000000..139bc18 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/TPQuerySetNodeBuilder.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.builder; + +import java.util.Objects; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQuerySet; + +/** + * Builds query set as tree. + * + * @author Willem Cazander + * @version 1.0 May 29, 2015 + */ +public class TPQuerySetNodeBuilder extends AbstractTPQueryNodeBuilder,TPQuerySet,TPQuerySetNodeBuilder> { + + private final TPQuerySetBuilder treeRoot; + + /** + * Creates an query set node. + * @param treeRoot The root query set builder. + * @param parent The parent builder. + * @param name The query set name. + */ + public TPQuerySetNodeBuilder(TPQuerySetBuilder treeRoot,TPQuerySetNodeBuilder parent,String name) { + super(parent,new TPQuerySet(name)); + this.treeRoot=treeRoot; + } + + @Override + protected TPQuerySetNodeBuilder getBuilder() { + return this; + } + + @Override + protected void buildParent() { + Validate.validState(Objects.nonNull(getParent()),"build() on root node is illegal use buildTree()"); + getParent().addQuerySet(getValue()); + } + + /** + * Builds the tree and returns the parent query set builder. + * @return The builder. + */ + public TPQuerySetBuilder buildTree() { + Validate.validState(Objects.isNull(getParent()),"buildTree() only works on tree root node."); + treeRoot.addQuerySet(getValue()); + return treeRoot; + } + + // ------- + + /** + * Create a query. + * @param name The query name. + * @return The builder. + */ + public TPQueryBuilder> createQuery(String name) { + return new TPQueryBuilder>(treeRoot.getParent(),this,name,new TPQueryBuilderParent() { + @Override + public void buildChild(TPQuery query) { + getValue().addQuery(query); + } + }); + } + + /** + * Adds a query set. + * @param qs The query set to add. + * @return The builder. + */ + public TPQuerySetNodeBuilder addQuerySet(TPQuerySet qs) { + return make(build -> build.addQuerySet(qs)); + } + + /** + * Create a query set. + * @param name The query set name. + * @return The builder. + */ + public TPQuerySetNodeBuilder createQuerySet(String name) { + return new TPQuerySetNodeBuilder(treeRoot,this,name); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/package-info.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/package-info.java new file mode 100644 index 0000000..2d94af6 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/builder/package-info.java @@ -0,0 +1,6 @@ +/** + * Builders for query-sets and queries. + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.config.builder; diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/package-info.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/package-info.java new file mode 100644 index 0000000..6dedf7e --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/package-info.java @@ -0,0 +1,6 @@ +/** + * Config of the queries and languages,types,etc. + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.config; diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/AbstractTPQConfigValidatorParameterPattern.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/AbstractTPQConfigValidatorParameterPattern.java new file mode 100644 index 0000000..806c61e --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/AbstractTPQConfigValidatorParameterPattern.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.validate; + +import java.util.function.Function; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQueryParameter; + +/** + * Abstract pattern checker which used an Function to get the value to check the pattern against. + * + * @author Willem Cazander + * @version 1.0 June 1, 2015 + */ +public abstract class AbstractTPQConfigValidatorParameterPattern implements TPQConfigValidatorCheck { + + private final String pattern; + private final Function patternValue; + + /** + * Creates this pattern check. + * @param pattern The pattern to check. + * @param patternValue The function to get value to check. + */ + public AbstractTPQConfigValidatorParameterPattern(String pattern,Function patternValue) { + Validate.notNull(patternValue); + this.pattern=pattern; + this.patternValue=patternValue; + } + + @Override + public void validateQuery(TPQuery query) { + query.getQueryParameters().forEach(p -> { + String value = patternValue.apply(p); + Validate.notNull(value,"%s need non null value",this.getClass().getName()); + Validate.matchesPattern(value, pattern, "validation failed on query %s, parameter: %s value: %s does not match %s",query.getName(),p.getName(),value,pattern); + }); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidator.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidator.java new file mode 100644 index 0000000..1904642 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidator.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.validate; + +import org.apache.commons.lang3.Validate; + +/** + * Holds the query name pattern fot he config validator checker. + * + * @author Willem Cazander + * @version 1.0 June 1, 2015 + */ +public class TPQConfigValidator { + + private final String pattern; + private final TPQConfigValidatorCheck check; + + /** + * Creates an config validator. + * @param pattern The query name pattern. + * @param check The checker to validate the queries which match the pattern. + */ + public TPQConfigValidator(String pattern, TPQConfigValidatorCheck check) { + Validate.notBlank(pattern); + Validate.notNull(check); + this.pattern = pattern; + this.check = check; + } + + /** + * @return the pattern + */ + public String getPattern() { + return pattern; + } + + /** + * @return the check + */ + public TPQConfigValidatorCheck getCheck() { + return check; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheck.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheck.java new file mode 100644 index 0000000..67ec208 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheck.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.validate; + +import net.forwardfire.tpquery.model.TPQuery; + +/** + * validates the given query. + * + * @author Willem Cazander + * @version 1.0 May 17, 2015 + */ +public interface TPQConfigValidatorCheck { + + /** + * Validate this query. + * @param query The query to validate. + */ + void validateQuery(TPQuery query); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckDescriptionNotBlank.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckDescriptionNotBlank.java new file mode 100644 index 0000000..9f8d61b --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckDescriptionNotBlank.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.validate; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQuery; + +/** + * Checks the query description to a pattern. + * + * @author Willem Cazander + * @version 1.0 June 1, 2015 + */ +public final class TPQConfigValidatorCheckDescriptionNotBlank implements TPQConfigValidatorCheck { + + @Override + public void validateQuery(TPQuery query) { + Validate.notBlank(query.getDescription()); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckNamePattern.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckNamePattern.java new file mode 100644 index 0000000..df0640b --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckNamePattern.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.validate; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQuery; + +/** + * Checks the query name to a pattern. + * + * @author Willem Cazander + * @version 1.0 June 1, 2015 + */ +public final class TPQConfigValidatorCheckNamePattern implements TPQConfigValidatorCheck { + + private final String pattern; + + public TPQConfigValidatorCheckNamePattern(String pattern) { + Validate.matchesPattern("", pattern); + this.pattern=pattern; + } + + @Override + public void validateQuery(TPQuery query) { + Validate.matchesPattern(query.getName(), pattern); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckParameterDefaultValueNotBlank.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckParameterDefaultValueNotBlank.java new file mode 100644 index 0000000..fe2cf7c --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckParameterDefaultValueNotBlank.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.validate; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQuery; + +/** + * Checks the query parameters default value to a pattern. + * + * @author Willem Cazander + * @version 1.0 June 1, 2015 + */ +public final class TPQConfigValidatorCheckParameterDefaultValueNotBlank implements TPQConfigValidatorCheck { + + @Override + public void validateQuery(TPQuery query) { + query.getQueryParameters().forEach(p -> Validate.notBlank(p.getDefaultValue())); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckParameterNamePattern.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckParameterNamePattern.java new file mode 100644 index 0000000..fab1a1c --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckParameterNamePattern.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.validate; + +/** + * Checks the query parameters name to a pattern. + * + * @author Willem Cazander + * @version 1.0 June 1, 2015 + */ +public final class TPQConfigValidatorCheckParameterNamePattern extends AbstractTPQConfigValidatorParameterPattern { + + public TPQConfigValidatorCheckParameterNamePattern(String pattern) { + super(pattern,p -> p.getName()); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckParameterTypePattern.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckParameterTypePattern.java new file mode 100644 index 0000000..5fa8d9a --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckParameterTypePattern.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.validate; + +/** + * Checks the query parameters type to a pattern. + * + * @author Willem Cazander + * @version 1.0 June 1, 2015 + */ +public final class TPQConfigValidatorCheckParameterTypePattern extends AbstractTPQConfigValidatorParameterPattern { + + public TPQConfigValidatorCheckParameterTypePattern(String pattern) { + super(pattern,p -> p.getType()); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckParameterValueTypePattern.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckParameterValueTypePattern.java new file mode 100644 index 0000000..f709478 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/TPQConfigValidatorCheckParameterValueTypePattern.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.config.validate; + +/** + * Checks the query parameters value type to a pattern. + * + * @author Willem Cazander + * @version 1.0 June 1, 2015 + */ +public final class TPQConfigValidatorCheckParameterValueTypePattern extends AbstractTPQConfigValidatorParameterPattern { + + public TPQConfigValidatorCheckParameterValueTypePattern(String pattern) { + super(pattern,p -> p.getValueType()); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/package-info.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/package-info.java new file mode 100644 index 0000000..80a5826 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/config/validate/package-info.java @@ -0,0 +1,6 @@ +/** + * Extra query model validation checks. + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.config.validate; diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/model/AbstractTPQueryNode.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/AbstractTPQueryNode.java new file mode 100644 index 0000000..6dc0778 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/AbstractTPQueryNode.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; + +import net.forwardfire.tpquery.model.AbstractXMLMarshaller.Attribute; +import net.forwardfire.tpquery.model.AbstractXMLMarshaller.Element; + +/** + * AbstractTPQueryNode has the shared properties of an query(set) node. + * + * @author Willem Cazander + * @version 1.0 May 18, 2015 + */ +public abstract class AbstractTPQueryNode { + + private String name = null; + private String description = null; + private String language = null; + private Boolean template = null; + private Integer timeout = null; + private final List queryHints; + + public AbstractTPQueryNode() { + queryHints = new ArrayList<>(); + } + + /** + * @return the name + */ + @XmlAttribute(name=Attribute.NAME,required=AbstractXMLMarshaller.Meta.REQUIRED) + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the description + */ + @XmlElement(name=Element.QUERY_DESCRIPTION) + public String getDescription() { + return description; + } + + /** + * @param description the description to set + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * @return the language + */ + @XmlAttribute(name=Attribute.LANGUAGE) + public String getLanguage() { + return language; + } + + /** + * @param language the language to set + */ + public void setLanguage(String language) { + this.language = language; + } + + /** + * @return the template + */ + @XmlAttribute(name=Attribute.TEMPLATE) + public Boolean getTemplate() { + return template; + } + + /** + * @param template the template to set + */ + public void setTemplate(Boolean template) { + this.template = template; + } + + /** + * @return the timeout + */ + @XmlAttribute(name=Attribute.TIMEOUT) + public Integer getTimeout() { + return timeout; + } + + /** + * @param timeout the timeout to set + */ + public void setTimeout(Integer timeout) { + this.timeout = timeout; + } + + /** + * @return the queryHints + */ + @XmlElement(name=Element.QUERY_HINT) + public List getQueryHints() { + return queryHints; + } + + /** + * @param queryHint the queryHint to add + */ + public void addQueryHint(TPQueryHint queryHint) { + Objects.requireNonNull(queryHint); + queryHints.add(queryHint); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/model/AbstractXMLMarshaller.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/AbstractXMLMarshaller.java new file mode 100644 index 0000000..1d55b90 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/AbstractXMLMarshaller.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.model; + +/** + * AbstractXMLMarshaller has all jaxb meta info. + * + * @author Willem Cazander + * @version 1.0 Jan 16, 2015 + */ +abstract class AbstractXMLMarshaller { + + protected static final String XML_ENCODING = "UTF-8"; + + protected AbstractXMLMarshaller() { + } + + protected static class Meta { + protected static final boolean REQUIRED = true; + protected Meta() { + } + } + + protected static class Element { + protected static final String QUERY_SET = "query-set"; + protected static final String QUERY = "query"; + protected static final String QUERY_DESCRIPTION = "description"; + protected static final String QUERY_HINT = "hint"; + protected static final String QUERY_PARAMETER = "parameter"; + protected static final String QUERY_PART = "statement"; + protected Element() { + } + } + + protected static class Attribute { + protected static final String NAME = "name"; + protected static final String VALUE = "value"; + protected static final String TYPE = "type"; + protected static final String DEFAULT_VALUE = "defaultValue"; + protected static final String TIMEOUT = "timeout"; + protected static final String TEMPLATE = "template"; + protected static final String LANGUAGE = "language"; + protected static final String VALUE_TYPE = "valueType"; + protected static final String NULLABLE = "nullable"; + protected Attribute() { + } + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQuery.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQuery.java new file mode 100644 index 0000000..540c148 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQuery.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import net.forwardfire.tpquery.model.AbstractXMLMarshaller.Element; +import net.forwardfire.tpquery.statement.TPQStatement; +import net.forwardfire.tpquery.statement.TPQStatementMarshallerAdapter; + +/** + * Defines a query. + * + * @author Willem Cazander + * @version 1.0 Jan 14, 2015 + */ +public final class TPQuery extends AbstractTPQueryNode { + + private List queryParts; + private final List queryParameters; + + public TPQuery() { + queryParts = new ArrayList<>(); + queryParameters = new ArrayList<>(); + } + + public TPQuery(String name) { + this(); + setName(name); + } + + /** + * @return the queryParts + */ + @XmlElement(name=Element.QUERY_PART,required=AbstractXMLMarshaller.Meta.REQUIRED) + @XmlJavaTypeAdapter(TPQStatementMarshallerAdapter.class) + public List getQueryParts() { + return queryParts; + } + + public void setQueryParts(List parts) { + Objects.requireNonNull(parts,"Can't set null list"); + queryParts = parts; + } + + public void addQueryPart(TPQStatement queryPart) { + Objects.requireNonNull(queryPart,"Can't add null"); + queryParts.add(queryPart); + } + + /** + * @return the queryParameters + */ + @XmlElement(name=Element.QUERY_PARAMETER) + public List getQueryParameters() { + return queryParameters; + } + + public void addQueryParameter(TPQueryParameter queryParameter) { + Objects.requireNonNull(queryParameter,"Can't add null"); + Objects.requireNonNull(queryParameter.getName(),"TQueryParameter.getName() is null."); + queryParameters.add(queryParameter); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQueryHint.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQueryHint.java new file mode 100644 index 0000000..cda1aa1 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQueryHint.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.model; + +import javax.xml.bind.annotation.XmlAttribute; + +import net.forwardfire.tpquery.model.AbstractXMLMarshaller.Attribute; + +/** + * Query hint are optional hint. + * + * @author Willem Cazander + * @version 1.0 Jan 14, 2015 + */ +public final class TPQueryHint { + + private String name = null; + private String value = null; + + public TPQueryHint() { + } + + public TPQueryHint(String name) { + this(); + setName(name); + } + + public TPQueryHint(String name,String value) { + this(name); + setValue(value); + } + + /** + * @return the name + */ + @XmlAttribute(name=Attribute.NAME,required=AbstractXMLMarshaller.Meta.REQUIRED) + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the value + */ + @XmlAttribute(name=Attribute.VALUE,required=AbstractXMLMarshaller.Meta.REQUIRED) + public String getValue() { + return value; + } + + /** + * @param value the value to set + */ + public void setValue(String value) { + this.value = value; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQueryParameter.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQueryParameter.java new file mode 100644 index 0000000..6843e6a --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQueryParameter.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.model; + +import javax.xml.bind.annotation.XmlAttribute; + +import net.forwardfire.tpquery.model.AbstractXMLMarshaller.Attribute; + +/** + * Defines the query parameter. + * + * @author Willem Cazander + * @version 1.0 Jan 14, 2015 + */ +public final class TPQueryParameter { + + private String name = null; + private String defaultValue = null; + private String type = null; + private String valueType = null; + private Boolean nullable = null; + + public TPQueryParameter() { + } + + public TPQueryParameter(String name,String valueType) { + setName(name); + setValueType(valueType); + } + + /** + * @return the name + */ + @XmlAttribute(name=Attribute.NAME,required=AbstractXMLMarshaller.Meta.REQUIRED) + public String getName() { + return name; + } + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the defaultValue + */ + @XmlAttribute(name=Attribute.DEFAULT_VALUE) + public String getDefaultValue() { + return defaultValue; + } + + /** + * @param defaultValue the defaultValue to set + */ + public void setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + } + + /** + * @return the type + */ + @XmlAttribute(name=Attribute.TYPE) + public String getType() { + return type; + } + + /** + * @param type the type to set + */ + public void setType(String type) { + this.type = type; + } + + /** + * @return the valueType + */ + @XmlAttribute(name=Attribute.VALUE_TYPE,required=AbstractXMLMarshaller.Meta.REQUIRED) + public String getValueType() { + return valueType; + } + + /** + * @param valueType the valueType to set + */ + public void setValueType(String valueType) { + this.valueType = valueType; + } + + /** + * @return the nullable + */ + @XmlAttribute(name=Attribute.NULLABLE) + public Boolean getNullable() { + return nullable; + } + + /** + * @param nullable the nullable to set + */ + public void setNullable(Boolean nullable) { + this.nullable = nullable; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQuerySet.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQuerySet.java new file mode 100644 index 0000000..ee457c2 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQuerySet.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.model; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import net.forwardfire.tpquery.model.AbstractXMLMarshaller.Element; + +/** + * Query sets is an tree node which holds more query sets and queries. + * + * @author Willem Cazander + * @version 1.0 Jan 14, 2015 + */ +@XmlRootElement(name=Element.QUERY_SET) +public class TPQuerySet extends AbstractTPQueryNode { + + private final List querySets; + private final List queries; + + public TPQuerySet() { + queries = new ArrayList<>(); + querySets = new ArrayList<>(); + } + + public TPQuerySet(String name) { + this(); + setName(name); + } + + /** + * @return the queries + */ + @XmlElement(name=Element.QUERY) + public List getQueries() { + return queries; + } + + /** + * @param query the query to add + */ + public void addQuery(TPQuery query) { + queries.add(query); + } + + /** + * @return the querySets + */ + @XmlElement(name=Element.QUERY_SET) + public List getQuerySets() { + return querySets; + } + + /** + * @param querySet the querySet to add + */ + public void addQuerySet(TPQuerySet querySet) { + querySets.add(querySet); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQuerySetXMLMarshaller.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQuerySetXMLMarshaller.java new file mode 100644 index 0000000..77d58b9 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/TPQuerySetXMLMarshaller.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.model; + +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Objects; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; + +/** + * Jaxb marshaller of the query sets. + * + * @author Willem Cazander + * @version 1.0 Jan 14, 2015 + */ +public class TPQuerySetXMLMarshaller extends AbstractXMLMarshaller { + + private final JAXBContext querySetContext; + + public TPQuerySetXMLMarshaller() throws JAXBException { + this(JAXBContext.newInstance(TPQuerySet.class)); + } + + public TPQuerySetXMLMarshaller(JAXBContext querySetContext) { + Objects.requireNonNull(querySetContext,"querySetContext is null."); + this.querySetContext = querySetContext; + } + + public void marshal(TPQuerySet querySet, OutputStream output) throws JAXBException { + Objects.requireNonNull(querySet,"querySet is null."); + Objects.requireNonNull(output,"OutputStream is null."); + + Marshaller marshaller = querySetContext.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.setProperty(Marshaller.JAXB_ENCODING, XML_ENCODING); + marshaller.marshal(querySet, output); + } + + public TPQuerySet unmarshal(InputStream input) throws JAXBException { + Objects.requireNonNull(input,"InputStream is null."); + + Unmarshaller unmarshaller = querySetContext.createUnmarshaller(); + return (TPQuerySet) unmarshaller.unmarshal(input); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/model/package-info.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/package-info.java new file mode 100644 index 0000000..f4a11c0 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/model/package-info.java @@ -0,0 +1,6 @@ +/** + * The query data model. + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.model; diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/package-info.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/package-info.java new file mode 100644 index 0000000..7d5153b --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/package-info.java @@ -0,0 +1,6 @@ +/** + * Templated Prepared Query manager and factory. + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery; diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/AbstractTPQStatement.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/AbstractTPQStatement.java new file mode 100644 index 0000000..465b339 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/AbstractTPQStatement.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQuery; + +/** + * Abstract implementation of a statement. + * + * @author Willem Cazander + * @version 1.0 May 21, 2015 + */ +public abstract class AbstractTPQStatement implements TPQStatement { + + private final String statementPart; + private TPQStatementContext context; + private TPQuery query; + + public AbstractTPQStatement(String statementPart) { + Validate.notNull(statementPart,"statementPart is null"); + this.statementPart=statementPart; + } + + @Override + public final void prepareInit(TPQStatementContext context, TPQuery query) { + this.context=context; + this.query=query; + prepareInit(); + } + + protected void prepareInit() { + } + + @Override + public final String getStatementPart() { + return statementPart; + } + + /** + * @return the context + */ + public final TPQStatementContext getContext() { + return context; + } + + /** + * @return the query + */ + public final TPQuery getQuery() { + return query; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/AbstractTPQStatementWriter.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/AbstractTPQStatementWriter.java new file mode 100644 index 0000000..645adc0 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/AbstractTPQStatementWriter.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.store.TPQueryStoreStatementMapper; + +/** + * Abstract implementation of the statement writer. + * + * @author Willem Cazander + * @version 1.0 May 20, 2015 + */ +public abstract class AbstractTPQStatementWriter implements TPQStatementWriter { + + protected static final String PARAMETER_PREPARED = "?"; + protected static final String PARAMETER_NEXT = ","; + private static final int OUTPUT_START_SIZE = 384; + + protected boolean flagValueBased = false; + protected final StringBuilder output; + protected final List queryParameterMapping; + protected final Map queryParameterData; + + public AbstractTPQStatementWriter(Map queryParameterData) { + Validate.notNull(queryParameterData); + this.queryParameterData=queryParameterData; + this.output = new StringBuilder(OUTPUT_START_SIZE); + this.queryParameterMapping = new ArrayList<>(); + } + + @Override + public void writeQuery(TPQuery query) { + Validate.notNull(query,"Can' write null query "); + query.getQueryParts().forEach(part -> part.prepare(this)); + } + + @Override + public Object getParameterValue(TPQueryParameter parameter) { + return queryParameterData.get(parameter.getName()); + } + + @Override + public boolean isValueMappedWriter() { + return true; + } + + @Override + public void appendQueryText(String text) { + Validate.notNull(text, "Can't add null text."); + output.append(text); + } + + @Override + public void appendQueryParameter(TPQueryStoreStatementMapper mapper) { + Validate.notNull(mapper); + queryParameterMapping.add(mapper); + output.append(PARAMETER_PREPARED); + } + + @Override + public void appendQueryParameterSeperator() { + output.append(PARAMETER_NEXT); + } + + @Override + public List getQueryParameterMapping() { + return queryParameterMapping; + } + + @Override + public String getQueryText() { + return output.toString(); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatement.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatement.java new file mode 100644 index 0000000..37ae47b --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatement.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement; + +import net.forwardfire.tpquery.model.TPQuery; + +/** + * Defines an query statement part. + * + * @author Willem Cazander + * @version 1.0 Jan 14, 2015 + */ +public interface TPQStatement { + + /** + * Init the query. + * @param context The prepare context. + * @param query The query to prepare. + */ + void prepareInit(TPQStatementContext context,TPQuery query); + + /** + * Writers all prepares statement parts to the query writer. + * @param queryWriter The query writer to build the prepared query with. + */ + void prepare(TPQStatementWriter queryWriter); + + /** + * @return the value of the statement part. + */ + String getStatementPart(); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementContext.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementContext.java new file mode 100644 index 0000000..84004a0 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementContext.java @@ -0,0 +1,78 @@ +/* + + + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement; + +import java.util.Map; + +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.statement.language.TPQStatementLanguage; +import net.forwardfire.tpquery.statement.parameter.TPQStatementParameter; + +/** + * Gives statement parts the needed references to data. + * + * @author Willem Cazander + * @version 1.0 May 14, 2015 + */ +public interface TPQStatementContext { + + /** + * Get a query by name. + * @param name The name of the query. + * @return The query. + */ + TPQuery getQuery(String name); + + /** + * Returns a statement type based on the parameter. + * @param param The parameter to get the statement parameter type for. + * @return The statement parameter. + */ + TPQStatementParameter getParameterType(TPQueryParameter param); + + /** + * Returns a statement language based on the query. + * @param query The query to get the statement language for. + * @return The statement language. + */ + TPQStatementLanguage getStatementLanguage(TPQuery query); + + /** + * Gets a query parameter by name. + * note: may move back to TPQuery + * + * @param query The query having the parameter. + * @param name The name of the paramter. + * @return The query parameter. + */ + TPQueryParameter getQueryParameterByName(TPQuery query,String name); + + /** + * Retuns an map to store context in while writing an prepared statement. + * @return The context map. + */ + Map getContextState(); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementMarshaller.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementMarshaller.java new file mode 100644 index 0000000..f67281a --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementMarshaller.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.apache.commons.lang3.Validate; + +/** + * Prints and parse the different statement parts. + * + * @author Willem Cazander + * @version 1.0 May 22, 2015 + */ +public class TPQStatementMarshaller { + + protected static final String DELIMITER = "$$"; + protected static final String INCLUDE_PREFIX = "inc:"; + private static final int DEFAULT_PRINT_SIZE = 384; + + public String marshal(List parts) { + Objects.requireNonNull(parts,"Can't print null list."); + StringBuilder buf = new StringBuilder(DEFAULT_PRINT_SIZE); + for (TPQStatement part : parts) { + if (part instanceof TPQStatementPartParameter) { + buf.append(DELIMITER); + buf.append(part.getStatementPart()); + buf.append(DELIMITER); + } else if (part instanceof TPQStatementPartInclude) { + buf.append(DELIMITER); + buf.append(INCLUDE_PREFIX); + buf.append(part.getStatementPart()); + buf.append(DELIMITER); + } else { + buf.append(part.getStatementPart()); + } + } + return buf.toString(); + } + + public List unmarshal(String statementTemplateText) { + Objects.requireNonNull(statementTemplateText,"Can't parse null text."); + List result = new ArrayList<>(); + parseLoop(result,statementTemplateText); + return result; + } + + private void appendText(List result,String text) { + if (text.isEmpty()) { + return; + } + result.add(new TPQStatementPartText(text)); + } + + private void parseLoop(List result,String value) { + + // search for start delimiter + int searchIndex = value.indexOf(DELIMITER); + if (searchIndex < 0) { + appendText(result,value); + return; // only text + } + + // search for end delimiter + int searchIndexEnd = value.indexOf(DELIMITER, searchIndex + DELIMITER.length()); + Validate.isTrue(searchIndexEnd > 0, "Can't parse token without end delimiter: %s",DELIMITER); + + // Split the template + String pre = value.substring(0,searchIndex); + String token = value.substring(searchIndex + DELIMITER.length(),searchIndexEnd); + String next = value.substring(searchIndexEnd + DELIMITER.length()); + + // Handle split results. + appendText(result,pre); + parseToken(result,token); + parseLoop(result,next); + } + + private void parseToken(List result,String token) { + Validate.notEmpty(token,"Can't parse empty token."); + if (token.startsWith(INCLUDE_PREFIX)) { + result.add(new TPQStatementPartInclude(token.substring(INCLUDE_PREFIX.length()))); + } else { + result.add(new TPQStatementPartParameter(token)); + } + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementMarshallerAdapter.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementMarshallerAdapter.java new file mode 100644 index 0000000..a32f16d --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementMarshallerAdapter.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; + +/** + * jaxb adapter to marshall the statement parts. + * + * @author Willem Cazander + * @version 1.0 Jan 15, 2015 + */ +public class TPQStatementMarshallerAdapter extends XmlAdapter> { + + protected final TPQStatementMarshaller statementMarshaller = new TPQStatementMarshaller(); + + @Override + public String marshal(List parts) throws Exception { + return statementMarshaller.marshal(ObjectUtils.defaultIfNull(parts, new ArrayList())); + } + + @Override + public List unmarshal(String value) throws Exception { + return statementMarshaller.unmarshal(StringUtils.defaultString(value)); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementPartInclude.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementPartInclude.java new file mode 100644 index 0000000..003d411 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementPartInclude.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement; + +import java.util.Objects; + +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.forwardfire.tpquery.model.TPQuery; + +/** + * Handles query include statement parts. + * + * @author Willem Cazander + * @version 1.0 Jan 16, 2015 + */ +public class TPQStatementPartInclude extends AbstractTPQStatement { + + private static final Logger LOG = LoggerFactory.getLogger(TPQStatementPartInclude.class); + private TPQuery includeQuery; + + /** + * Creates an query include part. + * @param value The part value. + */ + public TPQStatementPartInclude(String value) { + super(value); + LOG.trace(" include part created {}",value); + } + + @Override + public void prepareInit() { + String key = getQuery().getName(); + LOG.trace("init add loop lock: {}",key); + Validate.isTrue(Objects.isNull(getContext().getContextState().get(key)), "Duplicate treeLock key: %s", key); + getContext().getContextState().put(key,getClass().getName()); + + LOG.trace("init lookup query: {}",getStatementPart()); + includeQuery = getContext().getQuery(getStatementPart()); + Validate.isTrue(includeQuery.getTemplate(), "query: %s is not a template.", includeQuery.getName()); + + LOG.trace("init prepare included query."); // so all parameters are copies down the tree. + includeQuery.getQueryParts().forEach(part -> part.prepareInit(getContext(), includeQuery)); + + LOG.debug("init copy parameters: {} to: {}",includeQuery.getQueryParameters().size(),getQuery().getQueryParameters().size()); + getQuery().getQueryParameters().addAll(includeQuery.getQueryParameters()); + + LOG.trace("init remove loop lock: {}",key); + getContext().getContextState().remove(key); + } + + @Override + public void prepare(TPQStatementWriter queryWriter) { + queryWriter.writeQuery(includeQuery); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementPartParameter.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementPartParameter.java new file mode 100644 index 0000000..3455f47 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementPartParameter.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement; + +import net.forwardfire.tpquery.model.TPQueryParameter; + +/** + * Handles parameter statement parts. + * + * @author Willem Cazander + * @version 1.0 Jan 16, 2015 + */ +public class TPQStatementPartParameter extends AbstractTPQStatement { + + private TPQueryParameter parameter; + + /** + * Creates parameter statement part. + * @param value The part value. + */ + public TPQStatementPartParameter(String value) { + super(value); + } + + @Override + public void prepareInit() { + parameter = getContext().getQueryParameterByName(getQuery(),getStatementPart()); + } + + @Override + public void prepare(TPQStatementWriter queryWriter) { + getContext().getParameterType(parameter).prepareParameter(queryWriter, parameter, queryWriter.getParameterValue(parameter)); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementPartText.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementPartText.java new file mode 100644 index 0000000..af7e09c --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementPartText.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement; + +/** + * Handles query text statement parts. + * + * @author Willem Cazander + * @version 1.0 Jan 15, 2015 + */ +public class TPQStatementPartText extends AbstractTPQStatement { + + public TPQStatementPartText(String statementPart) { + super(statementPart); + } + + @Override + public void prepare(TPQStatementWriter queryWriter) { + queryWriter.appendQueryText(getStatementPart()); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementWriter.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementWriter.java new file mode 100644 index 0000000..8507840 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/TPQStatementWriter.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement; + +import java.util.List; + +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.store.TPQueryStoreStatementMapper; + +/** + * Writes the statement query as text, and holds the parameter mapping for it. + * + * @author Willem Cazander + * @version 1.0 May 17, 2015 + */ +public interface TPQStatementWriter { + + /** + * Write all query parts. + * @param query The query to write. + */ + void writeQuery(TPQuery query); + + + Object getParameterValue(TPQueryParameter parameter); + + /** + * Defines if this writer supports the statement value mapper. + * @return false if the mapper are used directly by this writer. + */ + boolean isValueMappedWriter(); + + /** + * Append query text to the statement. + * @param text The query part text to add. + */ + void appendQueryText(String text); + + void appendQueryParameter(TPQueryStoreStatementMapper valueMapper); + + void appendQueryParameterSeperator(); + + /** + * @return The parameter mapping for the writen query. + */ + List getQueryParameterMapping(); + + /** + * The statement query text. + * @return The statement query text. + */ + String getQueryText(); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/AbstractTPQStatementLanguage.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/AbstractTPQStatementLanguage.java new file mode 100644 index 0000000..2295dfb --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/AbstractTPQStatementLanguage.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement.language; + +import java.util.Map; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.statement.AbstractTPQStatementWriter; +import net.forwardfire.tpquery.statement.TPQStatementWriter; + +/** + * AbstractTQueryLanguageType holds the languageType key value and implements some default methods. + * + * @author Willem Cazander + * @version 1.0 May 22, 2015 + */ +public abstract class AbstractTPQStatementLanguage implements TPQStatementLanguage { + + private final String languageType; + + /** + * Creates the abstract language type. + * @param languageType The languageType key. + */ + public AbstractTPQStatementLanguage(String languageType) { + Validate.notNull(languageType, "languageType is null."); + this.languageType=languageType; + } + + @Override + public final String getLanguageType() { + return languageType; + } + + @Override + public TPQStatementWriter createQueryWriter(Map parameterData) { + return new TQueryStatementWriterPrepared(parameterData); + } + + private class TQueryStatementWriterPrepared extends AbstractTPQStatementWriter { + private TQueryStatementWriterPrepared(Map queryParameterData) { + super(queryParameterData); + } + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguage.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguage.java new file mode 100644 index 0000000..34c9cb8 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguage.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement.language; + +import java.util.Map; + +import net.forwardfire.tpquery.statement.TPQStatementWriter; + +/** + * Allows for different language writers to define how the query is writen as statement text. + * + * @author Willem Cazander + * @version 1.0 May 18, 2015 + */ +public interface TPQStatementLanguage { + + /** + * The language type. + * @return The type of language. + */ + String getLanguageType(); + + /** + * Creates a statement writer for this language. + * @param parameterData The request parameter data. + * @return The writer for this data. + */ + TPQStatementWriter createQueryWriter(Map parameterData); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguageHql.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguageHql.java new file mode 100644 index 0000000..69a40ad --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguageHql.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement.language; + +import java.util.Map; + +import net.forwardfire.tpquery.statement.AbstractTPQStatementWriter; +import net.forwardfire.tpquery.statement.TPQStatementWriter; +import net.forwardfire.tpquery.store.TPQueryStoreStatementMapper; + +/** + * Writes parameters as jpa ordered query syntax. + * + * @author Willem Cazander + * @version 1.0 May 18, 2015 + */ +public class TPQStatementLanguageHql extends AbstractTPQStatementLanguage { + + /** + * Creates the hql language type. + * @param languageType The languageType key. + */ + public TPQStatementLanguageHql(String languageType) { + super(languageType); + } + + @Override + public TPQStatementWriter createQueryWriter(Map parameterData) { + return new TQueryStatementWriterPreparedHql(parameterData); + } + + private class TQueryStatementWriterPreparedHql extends AbstractTPQStatementWriter { + private TQueryStatementWriterPreparedHql(Map queryParameterData) { + super(queryParameterData); + } + @Override + public void appendQueryParameter(TPQueryStoreStatementMapper valueMapper) { + super.appendQueryParameter(valueMapper); + output.append(this.queryParameterMapping.size()); + } + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguageSql.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguageSql.java new file mode 100644 index 0000000..fcefeaf --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguageSql.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement.language; + +/** + * Writes parameters as jdbc prepared statement syntax. + * + * @author Willem Cazander + * @version 1.0 May 18, 2015 + */ +public class TPQStatementLanguageSql extends AbstractTPQStatementLanguage { + + /** + * Creates the sql language type. + * @param languageType The languageType key. + */ + public TPQStatementLanguageSql(String languageType) { + super(languageType); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/package-info.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/package-info.java new file mode 100644 index 0000000..57ee680 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/language/package-info.java @@ -0,0 +1,6 @@ +/** + * Writer support for different parameterized query languages. + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.statement.language; diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/package-info.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/package-info.java new file mode 100644 index 0000000..1b44a56 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/package-info.java @@ -0,0 +1,6 @@ +/** + * Query statements are written from parts: TEXT,PARAMETER,INCLUDE + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.statement; diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/AbstractTPQStatementParameter.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/AbstractTPQStatementParameter.java new file mode 100644 index 0000000..7588f06 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/AbstractTPQStatementParameter.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement.parameter; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQueryParameter; + +/** + * AbstractTQueryTemplateType holds the templateType key value. + * + * @author Willem Cazander + * @version 1.0 May 22, 2015 + */ +public abstract class AbstractTPQStatementParameter implements TPQStatementParameter { + + private final String templateType; + + /** + * Creates the abstract template type. + * @param templateType The templateType key. + */ + public AbstractTPQStatementParameter(String templateType) { + Validate.notNull(templateType, "templateType is null."); + this.templateType=templateType; + } + + @Override + public final String getParameterType() { + return templateType; + } + + @Override + public void prepareValidate(TPQueryParameter param, Class valueType, Object paramValue) { + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameter.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameter.java new file mode 100644 index 0000000..55cc251 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameter.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement.parameter; + +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.statement.TPQStatementWriter; + +/** + * writes,validate and creates cacheKey for parameter type. + * + * @author Willem Cazander + * @version 1.0 May 16, 2015 + */ +public interface TPQStatementParameter { + + /** + * @return The parameter type to handle. + */ + String getParameterType(); + + /** + * Validates the parameter value. + * @param param The query parameter. + * @param valueType The resolved query parameter type. + * @param value The parameter value. + */ + void prepareValidate(TPQueryParameter param, Class valueType, Object value); + + /** + * Appends cache key for this parameter if needed. + * @param keyBuf The cacheKey buffer to append to. + * @param param The query parameter. + * @param value The query parameter value. + * @return returns true if parameter is cachable, false if not. + */ + boolean prepareCacheKey(StringBuilder keyBuf,TPQueryParameter param, Object value); + + /** + * Appends the query parameter to the writer. + * @param queryWriter The statement writer. + * @param param The query parameter. + * @param value The parameter value. + */ + void prepareParameter(TPQStatementWriter queryWriter, TPQueryParameter param, Object value); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameterList.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameterList.java new file mode 100644 index 0000000..f945fc2 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameterList.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement.parameter; + +import java.util.List; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.statement.TPQStatementWriter; + +/** + * Appends the query parameter list values to the writer. + * + * @author Willem Cazander + * @version 1.0 May 17, 2015 + */ +public class TPQStatementParameterList extends AbstractTPQStatementParameter { + + /** + * Creates the parameter list template type. + * @param templateType The templateType key. + */ + public TPQStatementParameterList(String templateType) { + super(templateType); + } + + @Override + public void prepareValidate(TPQueryParameter param, Class valueType, Object value) { + Validate.notNull(value, "List parameter requires non null value."); + Validate.isInstanceOf(List.class, value, "List parameter requires java.util.List type not: %s",value.getClass().getName()); + List valueList = (List)value; + Validate.isTrue(!valueList.isEmpty(), "List parameter requires none empty list."); + Object checkFirst = valueList.get(0); + Validate.isInstanceOf(valueType, checkFirst , "List parameter value with name: "+param.getName()+" has wong type: "+param.getValueType()+" but is: "+checkFirst.getClass().getName()); + } + + @Override + public boolean prepareCacheKey(StringBuilder keyBuf,TPQueryParameter param, Object value) { + keyBuf.append(((List)value).size()); + return true; + } + + @SuppressWarnings("unchecked") + @Override + public void prepareParameter(TPQStatementWriter queryWriter, TPQueryParameter param, Object value) { + writeList(queryWriter, param.getName(), (List)value); + } + + private void writeList(TPQStatementWriter queryWriter,String parameterName, List valueList) { + for (int i=0;i parameters) { + List listData = (List)parameters.get(parameterName); + return listData.get(index); + } + + // ------- fast-serializable + + private void writeObject(ObjectOutputStream out) throws IOException { + out.writeUTF(parameterName); + out.writeInt(index); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + parameterName = in.readUTF(); + index = in.readInt(); + } + + @SuppressWarnings("unused") + private void readObjectNoData() throws ObjectStreamException { + throw new IllegalStateException(); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameterRaw.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameterRaw.java new file mode 100644 index 0000000..e4da55d --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameterRaw.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement.parameter; + +import java.util.Objects; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.statement.TPQStatementWriter; + +/** + * Prints the parameter value as text in the prepared statement. + * + * @author Willem Cazander + * @version 1.0 May 17, 2015 + */ +public class TPQStatementParameterRaw extends AbstractTPQStatementParameter { + + private final String printNull; + + /** + * Creates the raw template type. + * @param templateType The templateType key. + * @param printNull The null string to print if the value is null. + */ + public TPQStatementParameterRaw(String templateType,String printNull) { + super(templateType); + Validate.notNull(printNull, "printNull is null"); + this.printNull=printNull; + } + + @Override + public boolean prepareCacheKey(StringBuilder keyBuf,TPQueryParameter param, Object value) { + return false; + } + + @Override + public void prepareParameter(TPQStatementWriter queryWriter, TPQueryParameter param, Object value) { + queryWriter.appendQueryText(Objects.toString(value, printNull)); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameterValue.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameterValue.java new file mode 100644 index 0000000..6c29c30 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameterValue.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement.parameter; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.statement.TPQStatementWriter; + +/** + * Appends the query parameter to the writer. + * + * @author Willem Cazander + * @version 1.0 May 17, 2015 + */ +public class TPQStatementParameterValue extends AbstractTPQStatementParameter { + + /** + * Creates the parameter template type. + * @param templateType The templateType key. + */ + public TPQStatementParameterValue(String templateType) { + super(templateType); + } + + @Override + public void prepareValidate(TPQueryParameter param, Class valueType, Object paramValue) { + if (paramValue == null) { + return; + } + Validate.isInstanceOf(valueType, paramValue, "Parameter with name: "+param.getName()+" has wong type: "+param.getValueType()+" but is: "+paramValue.getClass().getName()); + } + + @Override + public boolean prepareCacheKey(StringBuilder keyBuf,TPQueryParameter param, Object value) { + return true; + } + + @Override + public void prepareParameter(TPQStatementWriter queryWriter, TPQueryParameter param, Object value) { + queryWriter.appendQueryParameter(new TPQStatementParameterValueMapper(param.getName())); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameterValueMapper.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameterValueMapper.java new file mode 100644 index 0000000..440e20f --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/TPQStatementParameterValueMapper.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.statement.parameter; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.util.Map; + +import net.forwardfire.tpquery.store.TPQueryStoreStatementMapper; + +/** + * Maps a parameter value as statement value. + * + * @author Willem Cazander + * @version 1.0 Jun 6, 2015 + */ +@SuppressWarnings("serial") +public class TPQStatementParameterValueMapper implements TPQueryStoreStatementMapper { + + private String parameterName; + + /** + * Creates a parameter value mapping. + * @param parameterName The parameter name to map. + */ + public TPQStatementParameterValueMapper(String parameterName) { + this.parameterName=parameterName; + } + + @Override + public Object getParameterValue(Map parameters) { + return parameters.get(parameterName); + } + + // ------- fast-serializable + + private void writeObject(ObjectOutputStream out) throws IOException { + out.writeUTF(parameterName); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + parameterName = in.readUTF(); + } + + @SuppressWarnings("unused") + private void readObjectNoData() throws ObjectStreamException { + throw new IllegalStateException(); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/package-info.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/package-info.java new file mode 100644 index 0000000..6ac73ac --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/statement/parameter/package-info.java @@ -0,0 +1,6 @@ +/** + * Statement parameter types: VALUE,LIST,RAW + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.statement.parameter; diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryParameterMetaData.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryParameterMetaData.java new file mode 100644 index 0000000..1fee326 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryParameterMetaData.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store; + +/** + * Gives access to the parameter meta data. + * + * @author Willem Cazander + * @version 1.0 May 27, 2015 + */ +public interface TPQueryParameterMetaData { + + /** + * @return The name of the parameter. + */ + String getName(); + + /** + * @return The valueType of the parameter. + */ + Class getValueType(); + + /** + * @return True if the parameter is allowed null. + */ + boolean isNullable(); + + /** + * @return True is the parameter is required. + */ + boolean isRequired(); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStore.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStore.java new file mode 100644 index 0000000..156246c --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStore.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store; + +import java.util.List; +import java.util.Map; + +/** + * TPQueryStore validates and configures the config from the query store config. + * And provides access to the prepared queries and parameters. + * s + * @author Willem Cazander + * @version 1.0 Feb 14, 2015 + */ +public interface TPQueryStore { + + /** + * @return Returns sorted list of all queries able to execute. + */ + List getQueryNames(); + + /** + * Returns the parameter meta data of an query. + * @param queryName The query to get the parameter meta data for. + * @return The map with the parameter meta data. + */ + Map getParameterMetaData(String queryName); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreScriptEngine.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreScriptEngine.java new file mode 100644 index 0000000..adb43bc --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreScriptEngine.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store; + +import javax.script.Compilable; +import javax.script.Invocable; +import javax.script.ScriptEngine; + +/** + * Wrapped the optional script engine interfaces into a single interface. + * + * This can be used with an proxy instance so there are no casts needed in code. + * + * @author Willem Cazander + * @version 1.0 Jun 4, 2015 + */ +public interface TPQueryStoreScriptEngine extends ScriptEngine,Compilable,Invocable { + +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreScriptEngineException.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreScriptEngineException.java new file mode 100644 index 0000000..f01df4b --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreScriptEngineException.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store; + +/** + * Wrappes script exceptions to runtime exception. + * + * @author Willem Cazander + * @version 1.0 Jun 7, 2015 + */ +@SuppressWarnings("serial") +public class TPQueryStoreScriptEngineException extends RuntimeException { + + /** + * @param cause The cause of this exception. + */ + public TPQueryStoreScriptEngineException(Exception cause) { + super(cause); + } + + /** + * @param message The message of this exception. + * @param cause The cause of this exception. + */ + public TPQueryStoreScriptEngineException(String message,Exception cause) { + super(message,cause); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreStatement.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreStatement.java new file mode 100644 index 0000000..de35a02 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreStatement.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * Holds the written statements and meta info. + * + * @author Willem Cazander + * @version 1.0 May 27, 2015 + */ +@SuppressWarnings("serial") +public class TPQueryStoreStatement implements Serializable { + + private String name; + private String statement; + private String language; + private Integer timeout; + private Map properties; + private List valueMapping; + + public TPQueryStoreStatement(String name,String statement,String language,Integer timeout,Map properties,List valueMapping) { + Objects.requireNonNull(name,"name is null"); + Objects.requireNonNull(statement,"statement is null"); + Objects.requireNonNull(language,"language is null"); + Objects.requireNonNull(properties,"properties is null"); + this.name=name; + this.statement=statement; + this.timeout=timeout; // null is no timeout + this.language=language; + this.properties=Collections.unmodifiableMap(properties); + this.valueMapping=Collections.unmodifiableList(valueMapping); + } + + public String getName() { + return name; + } + + public String getStatement() { + return statement; + } + + public String getLanguage() { + return language; + } + + public Integer getTimeout() { + return timeout; + } + + public Map getProperties() { + return properties; + } + + public List getValueMapping() { + return valueMapping; + } + + // ------- fast-serializable + + private void writeObject(ObjectOutputStream out) throws IOException { + out.writeUTF(name); + out.writeUTF(statement); + out.writeUTF(language); + out.writeObject(timeout); + out.writeObject(new HashMap<>(properties)); + out.writeObject(new ArrayList<>(valueMapping)); + } + + @SuppressWarnings("unchecked") + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + name = in.readUTF(); + statement = in.readUTF(); + language = in.readUTF(); + timeout = (Integer)in.readObject(); + properties = Collections.unmodifiableMap((Map) in.readObject()); + valueMapping = Collections.unmodifiableList((List) in.readObject()); + } + + @SuppressWarnings("unused") + private void readObjectNoData() throws ObjectStreamException { + throw new IllegalStateException(); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreStatementCache.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreStatementCache.java new file mode 100644 index 0000000..25105c4 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreStatementCache.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store; + +/** + * Stores and retreives statements from a cache. + * + * @author Willem Cazander + * @version 1.0 Jun 6, 2015 + */ +public interface TPQueryStoreStatementCache { + + /** + * Store statement in cache. + * @param key The key to store the statement under. + * @param value The statement store in the cache. + */ + void put(String key,TPQueryStoreStatement value); + + /** + * Retreives an statement from the cache. + * @param key The key of the statement to retreive. + * @return The statement or null. + */ + TPQueryStoreStatement get(String key); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreStatementMapper.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreStatementMapper.java new file mode 100644 index 0000000..f810e8a --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/TPQueryStoreStatementMapper.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store; + +import java.io.Serializable; +import java.util.Map; + +/** + * Maps a single the named parameter to an ordered value. + * + * note: Don't inner-class this interface as it is Serializable. + * + * @author Willem Cazander + * @version 1.0 May 25, 2015 + */ +public interface TPQueryStoreStatementMapper extends Serializable { + + /** + * map the value from parameters. + * @param parameters The parameter map which contains our value. + * @return The value we need to have. + */ + Object getParameterValue(Map parameters); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/executor/AbstractTPQExecutor.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/executor/AbstractTPQExecutor.java new file mode 100644 index 0000000..90304aa --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/executor/AbstractTPQExecutor.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.executor; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.BiFunction; + +public abstract class AbstractTPQExecutor { + + private static final int PARAMETER_INDEX_START = 1; + private final TPQExecutorContext context; + private final Map> backendTypes; + + public AbstractTPQExecutor(TPQExecutorContext context) { + Objects.requireNonNull(context,"Can't execute with null context."); + this.context = context; + backendTypes = new HashMap<>(); + } + + protected void registrateStatementCreator(String language,BiFunction statementCreator) { + Objects.requireNonNull(language,"Can't registrate null language"); + Objects.requireNonNull(statementCreator,"Can't registrate null StatementCreator"); + backendTypes.put(language, statementCreator); + } + + protected final TPQExecutorContext getContext() { + return context; + } + + public S createPreparedStatement(C connection,String queryName,Map parameters) { + return prepare(connection,getContext().prepareQuery(queryName,parameters)); + } + + public int executeUpdate(C connection,String queryName) { + return executeUpdate(connection, queryName, null); + } + + public int executeUpdate(C connection,String queryName,Map parameters) { + return executeUpdate(createPreparedStatement(connection, queryName, parameters)); + } + + protected abstract int executeUpdate(S statement); + + protected abstract void prepareParameterValue(S statement,int index,Object value); + + protected void prepareParameters(S statement,TPQExecutorStatement query) { + List orderedParameters = query.getParameters(); + int parameterIndex=PARAMETER_INDEX_START; + for ( int i=0;i statementCreator = backendTypes.get(query.getLanguage()); + Objects.requireNonNull(statementCreator,"Unsupported language type: "+query.getLanguage()); + S result = statementCreator.apply(connection, query.getStatement()); + prepareParameters(result, query); + Integer timeout = query.getTimeout(); + if (timeout != null) { + prepareTimeout(result, timeout); + } + return result; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/executor/TPQExecutorContext.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/executor/TPQExecutorContext.java new file mode 100644 index 0000000..8137e87 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/executor/TPQExecutorContext.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.executor; + +import java.util.Map; + +/** + * TQueryExecutorContext creates and prepared statement for the executor. + * + * later: add logQueryTime(); etc + * + * @author Willem Cazander + * @version 1.0 Jan 19, 2015 + */ +public interface TPQExecutorContext { + + /** + * Creates an TQueryPrepared with statement for the queryName and parameters. + * @param queryName The queryName to prepare. + * @param parameters The parameters for statement. + * @return The TQueryPrepared. + */ + TPQExecutorStatement prepareQuery(String queryName,Map parameters); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/executor/TPQExecutorStatement.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/executor/TPQExecutorStatement.java new file mode 100644 index 0000000..5da8403 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/executor/TPQExecutorStatement.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.executor; + +import java.util.List; +import java.util.Map; + +/** + * + * + * @author Willem Cazander + * @version 1.0 Jan 14, 2015 + */ +public interface TPQExecutorStatement { + + String getName(); + + String getStatement(); + + List getParameters(); + + Integer getTimeout(); + + String getLanguage(); + + Map getProperties(); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/executor/package-info.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/executor/package-info.java new file mode 100644 index 0000000..4bc9483 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/executor/package-info.java @@ -0,0 +1,6 @@ +/** + * The objects which are for the executor. + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.store.executor; diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManager.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManager.java new file mode 100644 index 0000000..b20a9fa --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManager.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.manager; + +import java.util.Objects; + +import javax.script.CompiledScript; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.config.TPQConfig; +import net.forwardfire.tpquery.statement.TPQStatementContext; +import net.forwardfire.tpquery.store.TPQueryStore; +import net.forwardfire.tpquery.store.TPQueryStoreScriptEngineException; +import net.forwardfire.tpquery.store.executor.TPQExecutorContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Holds the query store and the executor context. + * + * @author Willem Cazander + * @version 1.0 May 27, 2015 + */ +public class TPQStoreManager implements TPQManager { + + private static final Logger LOG = LoggerFactory.getLogger(TPQStoreManager.class); + private final TPQueryStore queryStore; + private final TPQExecutorContext executorContext; + + /** + * Creates an TPQStoreManager with the config. + * @param config The config to create this manager for. + */ + public TPQStoreManager(TPQConfig config) { + this(new TPQStoreManagerConfig(config)); + } + + private TPQStoreManager(TPQStoreManagerConfig config) { + Objects.requireNonNull(config); + this.queryStore = new TPQStoreManagerEntryView(config); + TPQStatementContext statementContext = new TPQStoreManagerStatementContext(config); + this.executorContext = new TPQStoreManagerExecutorContext(config,statementContext); + + initStore(config,statementContext); + } + + protected void initStore(TPQStoreManagerConfig config,TPQStatementContext statementContext) { + + LOG.debug("init value scripts: {}",config.getParameterValueScripts().size()); + config.getParameterValueScripts().forEach(scriptBody -> { + LOG.trace("init value script: \n{}",scriptBody); + try { + config.getParameterValueEngine().eval(scriptBody); + } catch (Exception e) { + throw new TPQueryStoreScriptEngineException(e); + } + }); + + LOG.debug("init query entries: {}",config.getEntries().size()); + for (String qName:config.getEntries().keySet()) { + TPQStoreManagerEntry entry = config.getEntries().get(qName); + if (entry.getQuery().getTemplate()) { + continue; // are done by include + } + LOG.trace("init query entry: {}",qName); + + entry.getQuery().getQueryParts().forEach(part -> part.prepareInit(statementContext, entry.getQuery())); + entry.initEntry(); + entry.getQuery().getQueryParameters().forEach(param -> { + if (param.getDefaultValue()==null) { + return; + } + String scriptBody = config.getParameterValueScripter().convertDefaultValueToScript(param); + + LOG.trace("compiled parameter: {} default: {} into script: \n{}",param.getName(),param.getDefaultValue() ,scriptBody); + try { + CompiledScript script = config.getParameterValueEngine().compile(scriptBody); + entry.getParameterDefaultCompiledScripts().put(param.getName(), script); + } catch (Exception e) { + throw new TPQueryStoreScriptEngineException(e); + } + }); + } + LOG.info("StoreManager created with: {} queries.", config.getEntries().size()); + } + + @Override + public TPQueryStore getQueryStore() { + return queryStore; + } + + @Override + public TPQExecutorContext getQueryExecutorContext() { + return executorContext; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerConfig.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerConfig.java new file mode 100644 index 0000000..e98a5aa --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerConfig.java @@ -0,0 +1,203 @@ +package net.forwardfire.tpquery.store.manager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.forwardfire.tpquery.config.AbstractTPQConfig; +import net.forwardfire.tpquery.config.TPQConfig; +import net.forwardfire.tpquery.model.AbstractTPQueryNode; +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.model.TPQueryHint; +import net.forwardfire.tpquery.model.TPQuerySet; + +/** + * Hold the config for the manager. + * + * This copies all collections to read only once, then does some null checking. + * And most importandt build all the entry which hold the queries. + * + * @author Willem Cazander + * @version 1.0 May 25, 2015 + */ +public final class TPQStoreManagerConfig extends AbstractTPQConfig { + + private static final Logger LOG = LoggerFactory.getLogger(TPQStoreManagerConfig.class); + private final Map entries; + private final List queryNames; + + /** + * Creates this manager config. + * @param config The config to create this config for. + */ + public TPQStoreManagerConfig(TPQConfig config) { + super( + Collections.unmodifiableMap(new HashMap<>(config.getQuerySets())), + Collections.unmodifiableMap(new HashMap<>(config.getStatementParameters())), + Collections.unmodifiableMap(new HashMap<>(config.getStatementLanguages())), + Collections.unmodifiableMap(new HashMap<>(config.getValueTypeAliases())), + Collections.unmodifiableList(new ArrayList<>(config.getConfigValidators())), + Collections.unmodifiableList(new ArrayList<>(config.getParameterValueScripts())) + ); + treePathSeperator = config.getTreePathSeperator(); + defaultParameterType = config.getDefaultParameterType(); + defaultParameterNullable = config.getDefaultParameterNullable(); + statementCache = config.getStatementCache(); + parameterValueScripter = config.getParameterValueScripter(); + parameterValueEngine = config.getParameterValueEngine(); + LOG.trace("init<> created cloned config"); + + LOG.trace("init<> null validation"); + validateMap(getQuerySets(), "querySets"); + validateMap(getStatementParameters(), "statementParameters"); + validateMap(getStatementLanguages(), "statementLanguages"); + validateMap(getValueTypeAliases(), "valueTypeAliases"); + Validate.notNull(getTreePathSeperator(), "null treePathSeperator"); + Validate.notNull(getDefaultParameterType(), "null defaultParameterType"); + Validate.notNull(getDefaultParameterNullable(),"null defaultParameterNullable"); + Validate.notNull(getStatementCache(), "null statementCache"); + Validate.notNull(getParameterValueScripter(), "null parameterValueScripter"); + Validate.notNull(getParameterValueEngine(), "null parameterValueEngine"); + + LOG.trace("init<> build internal data"); + entries = Collections.unmodifiableMap(createEntries(config)); + queryNames = Collections.unmodifiableList(entries.keySet().stream().sorted().collect(Collectors.toList())); + + LOG.debug("init<> managed config created with {} queries.",entries.size()); + } + + private void validateMap(Map m,String name) { + Validate.notNull(m,"Map %m may not be null",name); + m.forEach((key,value) -> { + Validate.notNull(key,"key may not be null in %s",name); + Validate.notNull(value,"value may not be null in %s",name); + }); + } + + private Map createEntries(TPQConfig config) { + Map result = new HashMap<>(); + config.getQuerySets().forEach((String key,TPQuerySet qs) -> walkQuerySet(result,qs.getName(),qs,key) ); + return result; + } + + /** + * @return the entries + */ + public Map getEntries() { + return entries; + } + + /** + * @return the queryNames + */ + public List getQueryNames() { + return queryNames; + } + + private void walkQuerySet(Map result,String name,TPQuerySet qs,String systemId) { + Validate.notBlank(qs.getName(),"query set name may not be blank"); + qs.getQueryHints().forEach(hint -> { + Validate.notNull(hint.getName(), "query hint name not be null."); + Validate.notNull(hint.getValue(), "query hint value not be null of: "+hint.getName()); + }); + + // note: only imported on root sets as rest is handled by copyToChild because calling here again. + if (qs.getTemplate() == null) { + qs.setTemplate(false); + LOG.debug("Set default template value: {} on: {}.",qs.getTemplate(),name); + } + + for (TPQuerySet qsNode:qs.getQuerySets()) { + Validate.notNull(qsNode, "query set may not be null."); + + copyToChild(qs,qsNode); + walkQuerySet(result,name+getTreePathSeperator()+qsNode.getName(),qsNode,systemId); + } + for (TPQuery q:qs.getQueries()) { + Validate.notNull(q, "query may not be null."); + Validate.notBlank(q.getName(),"query name may not be blank"); + q.getQueryParameters().forEach(param -> { + Validate.notNull(param, "query parameter may not be null."); + Validate.notNull(param.getName(), "query parameter.getName() may not be null."); + Validate.notNull(param.getValueType(), "query parameter valueType may not be null."); + }); + + copyToChild(qs,q); + q.setName(name+getTreePathSeperator()+q.getName()); // set tree name. + + TPQStoreManagerEntry entry = createQueryEntry(q,systemId); // create fillQuery() ? and move back below. + + getConfigValidators().forEach(validator -> { + if (Pattern.matches(validator.getPattern(), q.getName())) { + LOG.debug("validation by: {} on query: {} because matched: {}",validator.getCheck().getClass().getSimpleName(),q.getName(),validator.getPattern()); + validator.getCheck().validateQuery(q); + } + }); + + result.put(entry.getQuery().getName(),entry); + } + } + + private void copyToChild(AbstractTPQueryNode parent,AbstractTPQueryNode child) { + + child.setLanguage(ObjectUtils.defaultIfNull(child.getLanguage(), parent.getLanguage())); + child.setTimeout( ObjectUtils.defaultIfNull(child.getTimeout(), parent.getTimeout())); + child.setTemplate(ObjectUtils.defaultIfNull(child.getTemplate(), parent.getTemplate())); + + for (TPQueryHint hint:parent.getQueryHints()) { + boolean add = true; + for (TPQueryHint childHint:child.getQueryHints()) { + if (hint.getName().equals(childHint.getName())) { + add = false; + break; + } + } + if (add) { + child.addQueryHint(hint); + } + } + } + + private TPQStoreManagerEntry createQueryEntry(TPQuery q,String systemId) { + TPQStoreManagerEntry entry = new TPQStoreManagerEntry(q,systemId); + + LOG.debug("Created store entry for query: {} systemId: {}",entry.getQuery().getName(),entry.getSystemId()); + + q.getQueryHints().forEach(hint -> { + entry.getNamedProperties().put(hint.getName(), hint.getValue()); + LOG.trace("Mapped query hint name: {} value {}",hint.getName(),hint.getValue()); + }); + + for (TPQueryParameter qp:q.getQueryParameters()) { + LOG.trace("Check parameter {}",qp.getName()); + + if (qp.getType() == null) { + qp.setType(getDefaultParameterType()); + LOG.debug("Set type on parameter: {} value: {} as default type.",qp.getName(),qp.getType()); + } + + // Autofill aliases to classes. + String valueTypeOld = qp.getValueType(); + qp.setValueType(ObjectUtils.defaultIfNull(getValueTypeAliases().get(qp.getValueType()), qp.getValueType())); + if (!valueTypeOld.equals(qp.getValueType())) { + LOG.debug("Converted alias for parameter: {} old: {} new: {}",qp.getName(),valueTypeOld,qp.getValueType()); + } + + if (qp.getNullable() == null) { + qp.setNullable(getDefaultParameterNullable()); + LOG.debug("Set nullable on parameter: {} value: {} as default type.",qp.getName(),qp.getNullable()); + } + } + return entry; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerEntry.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerEntry.java new file mode 100644 index 0000000..920da34 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerEntry.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.manager; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import javax.script.CompiledScript; + +import org.apache.commons.lang3.ClassUtils; + +import net.forwardfire.tpquery.config.TPQConfigParameterValueHolder; +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQueryHint; +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.store.TPQueryParameterMetaData; + +/** + * Hold al extra objects to prepare query the query. + * + * @author Willem Cazander + * @version 1.0 May 25, 2015 + */ +public final class TPQStoreManagerEntry { + + private long countPrepared = 0; + private long countCacheHit = 0; + private long countWrite = 0; + private final TPQuery query; + private final String systemId; + private boolean valueMappedWriter = true; + private boolean validateParameters = true; + private final Map namedProperties; + private final Map parameterDefaultCompiledScripts; + private final Map parameterDefaultValues; + private Map parameterMetaData; + private static final String HINT_VALIDATE = "net.forwardfire.tpquery.validate"; // LATER move to ? + + /** + * Create an entry for an query. + * @param query The query to create this entry for. + * @param systemId The systemId of the query. + */ + public TPQStoreManagerEntry(TPQuery query,String systemId) { + Objects.requireNonNull(query); + Objects.requireNonNull(systemId); + this.query=query; + this.systemId=systemId; + this.namedProperties=new HashMap<>(); + this.parameterDefaultCompiledScripts=new HashMap<>(); + this.parameterDefaultValues=new HashMap<>(); + for (TPQueryHint hint:query.getQueryHints()) { + if (HINT_VALIDATE.equals(hint.getName())) { + validateParameters = Boolean.parseBoolean(hint.getValue()); + break; + } + } + } + + /** + * Init extra data. + */ + public void initEntry() { + Map parameterMetaDataBuild = new HashMap<>(); + getQuery().getQueryParameters().forEach(p -> + parameterMetaDataBuild.put(p.getName(), + new TPQStoreManagerEntryParameterMetaData( + p.getName(),loadValueType(p.getValueType()),p.getNullable(),defineRequired(p) + ) + ) + ); + this.parameterMetaData=Collections.unmodifiableMap(parameterMetaDataBuild); + } + + private Class loadValueType(String valueType) { + try { + return ClassUtils.getClass(valueType); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException(e); + } + } + + private boolean defineRequired(TPQueryParameter p) { + return !p.getNullable() && Objects.isNull(p.getDefaultValue()); + } + + /** + * @return the query + */ + public TPQuery getQuery() { + return query; + } + + /** + * @return the systemId + */ + public String getSystemId() { + return systemId; + } + + /** + * @return the properties + */ + public Map getNamedProperties() { + return namedProperties; + } + + /** + * @return the parameterDefaultCompiledScripts + */ + public Map getParameterDefaultCompiledScripts() { + return parameterDefaultCompiledScripts; + } + + /** + * @return the parameterDefaultValues + */ + public Map getParameterDefaultValues() { + return parameterDefaultValues; + } + + /** + * @return the countPrepared + */ + public long getCountPrepared() { + return countPrepared; + } + + /** + * Increases the prepared counter. + */ + public void incCountPrepared() { + countPrepared++; + } + + /** + * @return the countCacheHit + */ + public long getCountCacheHit() { + return countCacheHit; + } + + /** + * Increases the cacheHit counter. + */ + public void incCountCacheHit() { + countCacheHit++; + } + + /** + * @return the countWrite + */ + public long getCountWrite() { + return countWrite; + } + + /** + * Increases the write counter. + */ + public void incCountWrite() { + countWrite++; + } + + /** + * @return the parameterMetaData + */ + public Map getParameterMetaData() { + return parameterMetaData; + } + + /** + * @return the valueMappedWriter + */ + public boolean isValueMappedWriter() { + return valueMappedWriter; + } + + /** + * @param valueMappedWriter the valueMappedWriter to set + */ + public void setValueMappedWriter(boolean valueMappedWriter) { + this.valueMappedWriter = valueMappedWriter; + } + + /** + * @return the validateParameters + */ + public boolean isValidateParameters() { + return validateParameters; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerEntryParameterMetaData.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerEntryParameterMetaData.java new file mode 100644 index 0000000..d4c7b06 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerEntryParameterMetaData.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.manager; + +import java.util.Objects; + +import net.forwardfire.tpquery.store.TPQueryParameterMetaData; + +/** + * Public implementation of the query parameter meta data. + * + * @author Willem Cazander + * @version 1.0 May 28, 2015 + */ +public class TPQStoreManagerEntryParameterMetaData implements TPQueryParameterMetaData { + + private final String name; + private final Class valueType; + private final boolean nullable; + private final boolean required; + + /** + * Create an info for the parameter. + * @param name The parameter name. + * @param valueType The parameter type. + */ + public TPQStoreManagerEntryParameterMetaData(String name,Class valueType,boolean nullable,boolean required) { + Objects.requireNonNull(name); + Objects.requireNonNull(valueType); + this.name=name; + this.valueType=valueType; + this.nullable=nullable; + this.required=required; + } + + @Override + public String getName() { + return name; + } + + @Override + public Class getValueType() { + return valueType; + } + + @Override + public boolean isNullable() { + return nullable; + } + + @Override + public boolean isRequired() { + return required; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerEntryView.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerEntryView.java new file mode 100644 index 0000000..0541f2a --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerEntryView.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.manager; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import net.forwardfire.tpquery.store.TPQueryParameterMetaData; +import net.forwardfire.tpquery.store.TPQueryStore; + +/** + * Provides access to the query store meta-info. + * + * @author Willem Cazander + * @version 1.0 May 27, 2015 + */ +public final class TPQStoreManagerEntryView implements TPQueryStore { + + private final TPQStoreManagerConfig config; + + /** + * Creates an TPQueryStore view based on the manager config. + * @param config The config from which the data comes. + */ + public TPQStoreManagerEntryView(TPQStoreManagerConfig config) { + Objects.requireNonNull(config); + this.config = config; + } + + @Override + public List getQueryNames() { + return config.getQueryNames(); + } + + @Override + public Map getParameterMetaData(String queryName) { + return config.getEntries().get(queryName).getParameterMetaData(); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerExecutorContext.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerExecutorContext.java new file mode 100644 index 0000000..6bf7283 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerExecutorContext.java @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.manager; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.script.CompiledScript; + +import net.forwardfire.tpquery.config.TPQConfigParameterValueHolder; +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.statement.TPQStatementContext; +import net.forwardfire.tpquery.statement.TPQStatementWriter; +import net.forwardfire.tpquery.statement.parameter.TPQStatementParameter; +import net.forwardfire.tpquery.store.TPQueryStoreScriptEngineException; +import net.forwardfire.tpquery.store.TPQueryStoreStatement; +import net.forwardfire.tpquery.store.executor.TPQExecutorContext; +import net.forwardfire.tpquery.store.executor.TPQExecutorStatement; + +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Prepares the query for the executor. + * + * This is done by writing the query statement or getting it from cache. + * And then mapping the parameters and returning it. + * + * @author Willem Cazander + * @version 1.0 May 27, 2015 + */ +public class TPQStoreManagerExecutorContext implements TPQExecutorContext { + + private static final Logger LOG = LoggerFactory.getLogger(TPQStoreManagerExecutorContext.class); + private final TPQStoreManagerConfig config; + private final TPQStatementContext statementContext; + + /** + * Creates then executor context. + * @param config The manager config from which we get the queries. + * @param statementContext The statement context with which the queries get written. + */ + public TPQStoreManagerExecutorContext(TPQStoreManagerConfig config,TPQStatementContext statementContext) { + Validate.notNull(config); + Validate.notNull(statementContext); + this.config = config; + this.statementContext=statementContext; + } + + @Override + public TPQExecutorStatement prepareQuery(String queryName,Map para) { + TPQStoreManagerEntry entry = config.getEntries().get(queryName); + Validate.notNull(entry, "Could not find query: %s",queryName); + return preparedQueryEntry(entry, para!=null?para:new HashMap<>()); + } + + private TPQExecutorStatement preparedQueryEntry(TPQStoreManagerEntry entry,Map para) { + LOG.debug("prepare query: {} parameterSize: {}",entry.getQuery().getName(),para.size()); + + // Throw exception if unknown parameter is given + if (entry.isValidateParameters()) { + checkIllegalParameters(entry, para); + } + + // Default values, valueType and cacheKey building from parameters + String cacheKey = prepareParameters(entry, para); + + // Get statement from cache if possible + TPQueryStoreStatement statement = null; + if (cacheKey != null) { + statement = config.getStatementCache().get(cacheKey); + LOG.trace("prepare cache get key: {} hit: {}",cacheKey,statement!=null); + if (statement!=null) { + entry.incCountCacheHit(); + } + } + + // write statement from query + if (statement == null) { + TPQuery query = entry.getQuery(); + TPQStatementWriter queryWriter = statementContext.getStatementLanguage(query).createQueryWriter(para); + queryWriter.writeQuery(query); + statement = createEntryStatement(entry,queryWriter); + + if (!queryWriter.isValueMappedWriter()) { // writer has disabled caching + if (entry.isValueMappedWriter()) { + entry.setValueMappedWriter(false); // set once + LOG.trace("prepare set value mapped writer: false"); + } + } else { + if (cacheKey != null) { // query has disabled caching + config.getStatementCache().put(cacheKey, statement); + LOG.trace("prepare cache put key: {}",cacheKey); + } + } + entry.incCountWrite(); + } + + // prepare statement for executor + entry.incCountPrepared(); + List prepareParameters = new ArrayList<>(); + statement.getValueMapping().forEach(mapper -> prepareParameters.add(mapper.getParameterValue(para))); + return new TPQStoreManagerExecutorStatement(statement,prepareParameters); + } + + private void checkIllegalParameters(TPQStoreManagerEntry entry,Map para) { + Set invalidParameters = new HashSet<>(para.keySet()); + entry.getQuery().getQueryParameters().forEach(param -> invalidParameters.remove(param.getName())); + Validate.isTrue(invalidParameters.isEmpty(),"Illegal parameters: %s",invalidParameters); + } + + private String prepareParameters(TPQStoreManagerEntry entry,Map para) { + StringBuilder keyBuf = null; + if (entry.isValueMappedWriter()) { + keyBuf = new StringBuilder(); + keyBuf.append(entry.getQuery().getName()); + keyBuf.append("$"); + } + for (int i=0;i para,TPQueryParameter param) { + String paramName = param.getName(); + Object paramValue = para.get(paramName); + LOG.debug("prepare parameter: {}",paramName); + + if (paramValue == null && param.getDefaultValue() != null) { + TPQConfigParameterValueHolder valueHolder = entry.getParameterDefaultValues().get(param.getName()); + if (valueHolder != null) { + paramValue = valueHolder.getValue(); + } else { + paramValue = resolveDefaultValue(entry, param); + } + para.put(paramName, paramValue); + LOG.debug("prepare fill default: {}",paramValue); + } + if (entry.isValidateParameters() && !param.getNullable()) { + Validate.notNull(paramValue,"parameter %s is not allowed to be null",param.getName()); + } + return paramValue; + } + + private TPQStatementParameter prepareParameterStatement(TPQStoreManagerEntry entry,TPQueryParameter param,Object paramValue) { + String paramName = param.getName(); + TPQStatementParameter paramType = statementContext.getParameterType(param); + Class valueType = entry.getParameterMetaData().get(paramName).getValueType(); + if (entry.isValidateParameters()) { + paramType.prepareValidate(param, valueType, paramValue); + } + return paramType; + } + + private Object resolveDefaultValue(TPQStoreManagerEntry entry,TPQueryParameter param) { + Object result = null; + CompiledScript script = entry.getParameterDefaultCompiledScripts().get(param.getName()); + Validate.notNull(script,"Should have had compiled script for: %s",param.getName()); + try { + result = script.eval(); + } catch (Exception e) { + throw new TPQueryStoreScriptEngineException("query: "+entry.getQuery().getName()+" param: "+param.getName()+" script: "+param.getDefaultValue(),e); + } + if (result instanceof TPQConfigParameterValueHolder) { + TPQConfigParameterValueHolder valueHolderResult = (TPQConfigParameterValueHolder)result; + entry.getParameterDefaultValues().put(param.getName(), valueHolderResult); + return valueHolderResult.getValue(); + } + return result; + } + + private TPQueryStoreStatement createEntryStatement(TPQStoreManagerEntry me,TPQStatementWriter qw) { + return new TPQueryStoreStatement( + me.getQuery().getName(), + qw.getQueryText(), + me.getQuery().getLanguage(), + me.getQuery().getTimeout(), + me.getNamedProperties(), + qw.getQueryParameterMapping() + ); + } + + /** + * @return Returns as text the counters stats. + */ + public List getCacheUsage() { // later move api via stats bean + opt jmx + List result = new ArrayList<>(); + for (TPQStoreManagerEntry entry:config.getEntries().values()) { + if (entry.getQuery().getTemplate()) { + continue; + } + result.add(String.format("%-35s prepared: %8d where writen: %8d and cache hits: %8d", + entry.getQuery().getName(), + entry.getCountPrepared(), + entry.getCountWrite(), + entry.getCountCacheHit() + )); + } + return result; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerExecutorStatement.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerExecutorStatement.java new file mode 100644 index 0000000..a257054 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerExecutorStatement.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.manager; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.store.TPQueryStoreStatement; +import net.forwardfire.tpquery.store.executor.TPQExecutorStatement; + +/** + * Is the implementation of the statement which gets executed by the executor. + * + * @author Willem Cazander + * @version 1.0 May 27, 2015 + */ +public final class TPQStoreManagerExecutorStatement implements TPQExecutorStatement { + + private final TPQueryStoreStatement statement; + private final List parameters; + + /** + * Creates the TPQStoreManagerExecutorStatement. + * @param statement The store statement. + * @param parameters The parameter values ordered. + */ + public TPQStoreManagerExecutorStatement(TPQueryStoreStatement statement,List parameters) { + Validate.notNull(statement,"statement is null"); + Validate.notNull(parameters,"parameters is null"); + this.statement=statement; + this.parameters=parameters; + } + + @Override + public List getParameters() { + return parameters; + } + + @Override + public String getName() { + return statement.getName(); + } + + @Override + public String getStatement() { + return statement.getStatement(); + } + + @Override + public Integer getTimeout() { + return statement.getTimeout(); + } + + @Override + public String getLanguage() { + return statement.getLanguage(); + } + + @Override + public Map getProperties() { + return statement.getProperties(); + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerStatementCache.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerStatementCache.java new file mode 100644 index 0000000..82eed32 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerStatementCache.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.manager; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import net.forwardfire.tpquery.store.TPQueryStoreStatement; +import net.forwardfire.tpquery.store.TPQueryStoreStatementCache; + +/** + * Simple r/w locked map based cache implementation. + * + * @author Willem Cazander + * @version 1.0 Jun 6, 2015 + */ +public class TPQStoreManagerStatementCache implements TPQueryStoreStatementCache { + + /** + * The default cache map initial capacity (MUST be a power of two) + */ + private static final int MAP_INITIAL_CAPACITY = 1 << 6; // aka 64 + + /** + * The cache data. + */ + private final Map cache; + + /** + * The cache read lock. + */ + private final Lock readLock; + + /** + * The cache write lock. + */ + private final Lock writeLock; + + /** + * Creates the statement cache. + */ + public TPQStoreManagerStatementCache() { + this(new HashMap<>(MAP_INITIAL_CAPACITY)); + } + + /** + * Creates the statement cache with storage. + * @param cache The storage of the cache. + */ + protected TPQStoreManagerStatementCache(Map cache) { + ReadWriteLock locker = new ReentrantReadWriteLock(); + this.readLock = locker.readLock(); + this.writeLock = locker.writeLock(); + this.cache = cache; + } + + /** + * @return the readLock + */ + protected Lock getReadLock() { + return readLock; + } + + /** + * @return the writeLock + */ + protected Lock getWriteLock() { + return writeLock; + } + + @Override + public void put(String key, TPQueryStoreStatement value) { + // note: when jacoco/cobatura/jdk fix try-with-resources convert to autoclosable + // currently AutoClosable are forbidden as they are not testable to 100%. + Lock locker = getWriteLock(); + try { + locker.lock(); + cache.put(key, value); + } finally { + locker.unlock(); + } + } + + @Override + public TPQueryStoreStatement get(String key) { + Lock locker = getReadLock(); + try { + locker.lock(); + return cache.get(key); + } finally { + locker.unlock(); + } + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerStatementContext.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerStatementContext.java new file mode 100644 index 0000000..a418d1f --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerStatementContext.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.manager; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import org.apache.commons.lang3.Validate; + +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.statement.TPQStatementContext; +import net.forwardfire.tpquery.statement.language.TPQStatementLanguage; +import net.forwardfire.tpquery.statement.parameter.TPQStatementParameter; + +/** + * Holds all data neede to write statements as query. + * + * @author Willem Cazander + * @version 1.0 May 27, 2015 + */ +public class TPQStoreManagerStatementContext implements TPQStatementContext { + + private final Map state; + private final TPQStoreManagerConfig config; + + /** + * Creates the TPQStoreManagerStatementContext. + * @param config The config from which we get the data. + */ + public TPQStoreManagerStatementContext(TPQStoreManagerConfig config) { + this.config = Validate.notNull(config); + this.state = new HashMap<>(); + } + + @Override + public TPQuery getQuery(String name) { + Validate.notNull(name,"Can't search null name "); + TPQStoreManagerEntry result = Validate.notNull(config.getEntries().get(name),"Could not find query: %s,",name); + return Validate.notNull(result.getQuery()); + } + + @Override + public TPQStatementParameter getParameterType(TPQueryParameter param) { + Objects.requireNonNull(param,"Can' search null parameter "); + return Objects.requireNonNull(config.getStatementParameters().get(param.getType()),"Could not find parameter type: "+param.getType()+" of: "+param.getName()); + } + + @Override + public TPQStatementLanguage getStatementLanguage(TPQuery query) { + Objects.requireNonNull(query,"Can' search null query "); + return Objects.requireNonNull(config.getStatementLanguages().get(query.getLanguage()),"Could not find language type: "+query.getLanguage()+" of: "+query.getName()); + } + + @Override + public TPQueryParameter getQueryParameterByName(TPQuery query, String name) { + Objects.requireNonNull(query,"Can' search null query "); + Objects.requireNonNull(name,"Can' search null name "); + TPQueryParameter result = null; + for (TPQueryParameter param:query.getQueryParameters()) { // note: slow path as only used in init, else mod data model. + if (name.equals(param.getName())) { + result = param; + break; + } + } + return Validate.notNull(result,"Coult not find query parameter with name: %s",name); + } + + @Override + public Map getContextState() { + return state; + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/package-info.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/package-info.java new file mode 100644 index 0000000..49262bd --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/manager/package-info.java @@ -0,0 +1,6 @@ +/** + * Implementation of store and manager plus contexts classes. + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.store.manager; diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/package-info.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/package-info.java new file mode 100644 index 0000000..228b756 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/package-info.java @@ -0,0 +1,6 @@ +/** + * Provides access to the stored query meta information. + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.store; diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/TPQueryName.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/TPQueryName.java new file mode 100644 index 0000000..217f740 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/TPQueryName.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.proxy; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Defines an optional custom query name binding to a method. + * + * @author Willem Cazander + * @version 1.0 Jun 19, 2015 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface TPQueryName { + + /** + * Sets an non default query name. + * It defaults to the method name. + * note: result is formatted with the method name as 1st parameter. + * + * @return The query name. + */ + String value() default "%s"; +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/TPQueryParameterName.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/TPQueryParameterName.java new file mode 100644 index 0000000..886875f --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/TPQueryParameterName.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.proxy; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Define the query parameter name of a method parameter. + * + * @author Willem Cazander + * @version 1.0 Jun 19, 2015 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +public @interface TPQueryParameterName { + + /** + * @return The query parameter name. + */ + String value(); +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/TPQueryProxy.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/TPQueryProxy.java new file mode 100644 index 0000000..e0aa400 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/TPQueryProxy.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.proxy; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks an interface as a query proxy target. + * + * @author Willem Cazander + * @version 1.0 Jun 19, 2015 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface TPQueryProxy { + + /** + * Sets an non default query prefix. + * It defaults to an empty string. + * note: result is formatted with the interface simple class name as 1st parameter. + * + * @return The prefix of the queries in the interface of the method. + */ + String prefix() default ""; +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/TPQueryProxyFactory.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/TPQueryProxyFactory.java new file mode 100644 index 0000000..bf47456 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/TPQueryProxyFactory.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2013-2015, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.forwardfire.tpquery.store.proxy; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; + +import org.apache.commons.lang3.Validate; + +/** + * Wraps method to functions based on the result type. + * + * @author Willem Cazander + * @version 1.0 Jun 19, 2015 + */ +public class TPQueryProxyFactory { + + private final ClassLoader classLoader; + private final Map,BiFunction,Object>> invokeHandlers; + + /** + * Creates an empty factory. + */ + public TPQueryProxyFactory() { + this(TPQueryProxyFactory.class.getClassLoader()); + } + + /** + * Creates an empty factory. + * @param classLoader The class loader to use for creating new proxies. + */ + public TPQueryProxyFactory(ClassLoader classLoader) { + this.invokeHandlers = new HashMap<>(); + this.classLoader = Validate.notNull(classLoader); + } + + /** + * Registrates an function handler for mapping methods result types to data. + * + * @param resultType The method result type to registrate the handler for. + * @param handler The function handler which convert string,parameters to an result of the resultType. + */ + public void registrateResultHandler(Class resultType, BiFunction,Object> handler) { + invokeHandlers.put(Validate.notNull(resultType),Validate.notNull(handler)); + } + + /** + * Creates an new proxy instance for the query interface class. + * + * @param queryInterface The class to make a query proxy for. + * @return The wired proxy. + */ + @SuppressWarnings("unchecked") + public T newProxyInstance(Class queryInterface) { + return (T)Proxy.newProxyInstance(classLoader, new Class[]{queryInterface}, new TPQueryExecutorProxyInvocationHandler(queryInterface)); + } + + private BiFunction,Object> lookupInvokeHandler(Class clazz) { + BiFunction,Object> handler = invokeHandlers.get(clazz); + if (handler == null) { + handler = invokeHandlers.get(Object.class); + } + return Validate.notNull(handler); + } + + class TPQueryExecutorProxyInvocationHandler implements InvocationHandler { + + private final Map,Object>> methodInvokers; + + public TPQueryExecutorProxyInvocationHandler(Class queryInterface) { + methodInvokers = new HashMap<>(); + TPQueryProxy queryProxy = Validate.notNull(queryInterface.getAnnotation(TPQueryProxy.class)); + String queryPrefix = String.format(queryProxy.prefix(),queryInterface.getSimpleName()); + for (Method method:queryInterface.getMethods()) { + TPQueryName query = method.getAnnotation(TPQueryName.class); + String queryName = queryPrefix + (query!=null?String.format(query.value(),method.getName()):method.getName()); + BiFunction,Object> handler = lookupInvokeHandler(method.getReturnType()); + Function,Object> invoker = parameters -> handler.apply(queryName, parameters); + methodInvokers.put(method, invoker); + } + } + + // move to functions ? + private Map mapParameters(Method method,Object[] args) { + Map parameters = new HashMap<>(); + int idx=0; + for (Parameter para:method.getParameters()) { + Object value = args[idx++]; + TPQueryParameterName queryParameter = Validate.notNull(para.getAnnotation(TPQueryParameterName.class)); + parameters.put(queryParameter.value(),value); + } + return parameters; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + return methodInvokers.get(method).apply(mapParameters(method,args)); + } + } +} diff --git a/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/package-info.java b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/package-info.java new file mode 100644 index 0000000..cb3a0f5 --- /dev/null +++ b/tpquery-store/src/main/java/net/forwardfire/tpquery/store/proxy/package-info.java @@ -0,0 +1,6 @@ +/** + * Wraps interface methods to query results. + * + * @author Willem Cazander + */ +package net.forwardfire.tpquery.store.proxy; diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/TPQFactoryTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/TPQFactoryTest.java new file mode 100644 index 0000000..473e31f --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/TPQFactoryTest.java @@ -0,0 +1,41 @@ +package net.forwardfire.tpquery; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.config.TPQConfig; + +public class TPQFactoryTest { + + @Test + public void testCreateConfig() throws Exception { + assertNotNull(TPQFactory.createConfig()); + } + + @Test + public void testBuildConfig() throws Exception { + assertNotNull(TPQFactory.createConfigBuilder()); + + TPQConfig config = TPQFactory.createConfigBuilder().createQuerySet("testA", "jar:junit:test").createQuery("test").build().build().build(); + assertNotNull(config); + } + + @Test + public void testBuildConfigMultiple() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + TPQFactory.createConfigBuilder(config).createQuerySet("testA", "jar:junit:testA").createQuery("test1").build().build().build(); + TPQFactory.createConfigBuilder(config).createQuerySet("testB", "jar:junit:testB").createQuery("test2").build().build().build(); + TPQManager manager = TPQFactory.createManager(config); + assertEquals(2,manager.getQueryStore().getQueryNames().size()); + } + + @Test() + public void testFactoryConstructors() throws Exception { + assertNotNull(new TPQFactory()); + assertNotNull(new TPQFactory.ParameterValueType()); + } +} + diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/TPQSpeedTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/TPQSpeedTest.java new file mode 100644 index 0000000..a67aa9a --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/TPQSpeedTest.java @@ -0,0 +1,436 @@ +package net.forwardfire.tpquery; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.LoggerContext; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.store.TPQueryStoreStatementMapper; +import net.forwardfire.tpquery.store.TPQueryStoreStatement; +import net.forwardfire.tpquery.store.manager.TPQStoreManagerExecutorContext; +import net.forwardfire.tpquery.store.manager.TPQStoreManagerExecutorStatement; + +public class TPQSpeedTest { + + static int loopSize; + static int warmupSize; + static TPQManager queryManager; + static List result; + + @BeforeClass + static public void initSpeedTest() throws Exception { + + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + lc.reset(); // disable logging in speed tests. + + warmupSize = 10; + loopSize = 100000*new Integer(System.getProperty("junit.speedtest.factor", "1")); + result = new ArrayList<>(); + queryManager = TPQFactory.createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("speed-prepared-novalidate") + .parseStatement("select * from foobar where $$inc:junit.inc-para$$ $$inc:junit.inc-raw-fake$$") + .addQueryHint("net.forwardfire.tpquery.validate", "false") + .build() + .createQuery("speed-prepared") + .parseStatement("select * from foobar where $$inc:junit.inc-para$$ $$inc:junit.inc-raw-fake$$") // keep para+incl count equal + .build() + .createQuery("speed-raw") + .parseStatement("select * from foobar where $$inc:junit.inc-para$$ $$inc:junit.inc-raw$$") + .build() + .createQuery("inc-para") + .setTemplate(true) + .parseStatement("a=$$a$$ and b=$$b$$$ and c=$$c$$ and d in ($$d$$) and e in ($$e$$)") + .createQueryParameter("a", TPQFactory.ParameterValueType.INTEGER) + .setDefaultValue("123") + .build() + .createQueryParameter("b", TPQFactory.ParameterValueType.STRING) + .setDefaultValue("abc") + .build() + .createQueryParameter("c", TPQFactory.ParameterValueType.BOOLEAN) + .setDefaultValue("true") + .build() + .createQueryParameter("d", TPQFactory.ParameterValueType.INTEGER) + .setType(TPQFactory.StatementParameter.LIST) + .setDefaultValue("10,11,12,13,14,15,16,17,18,19") + .build() + .createQueryParameter("e", TPQFactory.ParameterValueType.INTEGER) + .setType(TPQFactory.StatementParameter.LIST) + .setDefaultValue("20,21,22,23,24,25,26,27,28,29") + .build() + .build() + .createQuery("inc-raw") + .setTemplate(true) + .parseStatement(" AND f=$$f$$") + .createQueryParameter("f", TPQFactory.ParameterValueType.STRING) + .setType(TPQFactory.StatementParameter.RAW) + .setDefaultValue("sqlfunction(abs(select from abc group by def_col))") + .build() + .build() + .createQuery("inc-raw-fake") + .setTemplate(true) + .parseStatement(" AND f=$$f$$") + .createQueryParameter("f", TPQFactory.ParameterValueType.STRING) + .setType(TPQFactory.StatementParameter.VALUE) + .setDefaultValue("sqlfunction('abs')") + .build() + .build() + .createQuery("speed-function-dynamic") + .parseStatement("select * from foobar where a=$$a$$ and b in ($$b$$)") + .createQueryParameter("a", TPQFactory.ParameterValueType.INTEGER) + .setDefaultValue("js:createObject(java.lang.Integer,'123');") + .build() + .createQueryParameter("b", TPQFactory.ParameterValueType.INTEGER) + .setType(TPQFactory.StatementParameter.LIST) + .setDefaultValue("js:createObjectList(java.lang.Integer,'10,11,12,13,14,15,16,17,18,19');") + .build() + .build() + .createQuery("speed-function-holded") + .parseStatement("select * from foobar where a=$$a$$ and b in ($$b$$)") + .createQueryParameter("a", TPQFactory.ParameterValueType.INTEGER) + .setDefaultValue("js:createValueHolder(createObject(java.lang.Integer,'123'));") + .build() + .createQueryParameter("b", TPQFactory.ParameterValueType.INTEGER) + .setType(TPQFactory.StatementParameter.LIST) + .setDefaultValue("js:createValueHolder(createObjectList(java.lang.Integer,'10,11,12,13,14,15,16,17,18,19'));") + .build() + .build() + .build() + .build(); + + // warmup + Map para1 = new HashMap<>(); // FIXME: ??? defaults are adding in this maps + Map para2 = new HashMap<>(); + Map para3 = new HashMap<>(); + Map para4 = new HashMap<>(); + for (int i=0;i> tasks = new ArrayList<>(); + int size = 1*loopSize; + for (int i=0;i() { + @Override + public Boolean call() throws Exception { + r.run(ii); + return true; + } + }); + } + + ExecutorService exe = Executors.newFixedThreadPool(threads); + long start = System.currentTimeMillis(); + tasks.forEach(task -> exe.submit(task)); + exe.shutdown(); + exe.awaitTermination(5, TimeUnit.MINUTES); + long total = System.currentTimeMillis()-start; + float tps = size/(total/1000f); + + result.add(String.format("%-30s in %7d ms qps: %16f",r.name(),total,tps)); + } + + private void runTimed(SpeedTest r) { + int size = 1*loopSize; + long start = System.currentTimeMillis(); + for (int i=0;i createList(int i) { + List result = new ArrayList<>(); + result.add(i); + result.add(i*2); + result.add(i/3); + result.add((i+4)*5); + if ((i&1) == 0) { + result.add(i*2); + result.add(i/3); + } else { + for (int l=1;l<(i&(1+2+4+8+16));l++) { + result.add(l*i); + } + } + return result; + } + + @Test + public void testPreparedValuesDefaults() throws Exception { + runTimed(new SpeedTest() { + @Override + public void run(int i) { + Map para = new HashMap<>(); + queryManager.getQueryExecutorContext().prepareQuery("junit.speed-prepared", para); + } + + @Override + public String name() { + return "prepared-values-defaults"; + } + }); + } + + @Test + public void testPreparedValuesEqual() throws Exception { + Map para = new HashMap<>(); + para.put("a",123000); + para.put("b","123000"); + para.put("c",false); + para.put("d",Arrays.asList(1,2,3,4,5)); + para.put("e",Arrays.asList(6,7,8,9,0)); + para.put("f","raw"); + runTimed(new SpeedTest() { + @Override + public void run(int i) { + queryManager.getQueryExecutorContext().prepareQuery("junit.speed-prepared", para); + } + + @Override + public String name() { + return "prepared-values-equal"; + } + }); + } + + @Test + public void testPreparedValuesNonEqual() throws Exception { + Map para = new HashMap<>(); + runTimed(new SpeedTest() { + @Override + public void run(int i) { + para.put("a",123*i-i); + para.put("b",""+(345*i-i)); + para.put("c",(i&1)==0); + para.put("d",createList(i)); + para.put("e",createList(i)); + para.put("f","raw"+i); + queryManager.getQueryExecutorContext().prepareQuery("junit.speed-prepared", para); + } + + @Override + public String name() { + return "prepared-values-nonequal"; + } + }); + } + + @Test + public void testPreparedNoValidate() throws Exception { + Map para = new HashMap<>(); + runTimed(new SpeedTest() { + @Override + public void run(int i) { + para.put("a",123*i-i); + para.put("b",""+(345*i-i)); + para.put("c",(i&1)==0); + para.put("d",createList(i)); + para.put("e",createList(i)); + para.put("f","raw"+i); + queryManager.getQueryExecutorContext().prepareQuery("junit.speed-prepared-novalidate", para); + } + + @Override + public String name() { + return "prepared-novalidate"; + } + }); + } + + @Test + public void testRawValuesDefaults() throws Exception { + runTimed(new SpeedTest() { + @Override + public void run(int i) { + Map para = new HashMap<>(); + queryManager.getQueryExecutorContext().prepareQuery("junit.speed-raw", para); + } + + @Override + public String name() { + return "raw-values-defaults"; + } + }); + } + + @Test + public void testRawValuesEqual() throws Exception { + Map para = new HashMap<>(); + para.put("a",123000); + para.put("b","123000"); + para.put("c",false); + para.put("d",Arrays.asList(1,2,3,4,5)); + para.put("e",Arrays.asList(6,7,8,9,0)); + para.put("f","raw"); + runTimed(new SpeedTest() { + @Override + public void run(int i) { + queryManager.getQueryExecutorContext().prepareQuery("junit.speed-raw", para); + } + + @Override + public String name() { + return "raw-values-equal"; + } + }); + } + + @Test + public void testRawValuesNoneEqual() throws Exception { + Map para = new HashMap<>(); + runTimed(new SpeedTest() { + @Override + public void run(int i) { + para.put("a",123*i-i); + para.put("b",""+(345*i-i)); + para.put("c",(i&1)==0); + para.put("d",createList(i)); + para.put("e",createList(i)); + para.put("f","raw"+i); + queryManager.getQueryExecutorContext().prepareQuery("junit.speed-raw", para); + } + + @Override + public String name() { + return "raw-values-nonequal"; + } + }); + } + + @Test + public void testFunctionDynamic() throws Exception { + runTimed(new SpeedTest() { + @Override + public void run(int i) { + Map para = new HashMap<>(); + queryManager.getQueryExecutorContext().prepareQuery("junit.speed-function-dynamic", para); + } + + @Override + public String name() { + return "function-dynamic"; + } + }); + } + + @Test + public void testFunctionHolded() throws Exception { + runTimed(new SpeedTest() { + @Override + public void run(int i) { + Map para = new HashMap<>(); + queryManager.getQueryExecutorContext().prepareQuery("junit.speed-function-holded", para); + } + + @Override + public String name() { + return "function-holded"; + } + }); + } + + @Test + public void testReferenceLoop() throws Exception { + runTimed(new SpeedTest() { + @Override + public void run(int i) { + Map para = new HashMap<>(); + para.put("a",123*i-i); + para.put("b",""+(345*i-i)); + para.put("c",(i&1)==0); + para.put("d",createList(i)); + para.put("e",createList(i)); + para.put("f","raw"+i); + para.clear(); + + List valueMapping = new ArrayList<>(); + TPQueryStoreStatement entryStatement = new TPQueryStoreStatement(""+i,"nosql","ldap",-1,new HashMap<>(),valueMapping); + new TPQStoreManagerExecutorStatement(entryStatement,new ArrayList<>(para.values())); + } + + @Override + public String name() { + return "reference-loop"; + } + }); + } + + class ThreadedSpeedTest implements SpeedTest { + private final String name; + private final String queryName; + + public ThreadedSpeedTest(String name, String queryName) { + super(); + this.name = name; + this.queryName = queryName; + } + + @Override + public void run(int i) { + Map para = new HashMap<>(); + para.put("a",123*i-i); + para.put("b",""+(345*i-i)); + para.put("c",(i&1)==0); + para.put("d",createList(i)); + para.put("e",createList(i)); + para.put("f","raw"+i); + queryManager.getQueryExecutorContext().prepareQuery(queryName, para); + } + + @Override + public String name() { + return name; + } + } + + @Test + public void testRawThreaded() throws Exception { + + runTimedThreaded(new ThreadedSpeedTest("thread-2-speed-raw","junit.speed-raw"),2); + runTimedThreaded(new ThreadedSpeedTest("thread-4-speed-raw","junit.speed-raw"),4); + + runTimedThreaded(new ThreadedSpeedTest("thread-2-speed-prepared","junit.speed-prepared"),2); + runTimedThreaded(new ThreadedSpeedTest("thread-4-speed-prepared","junit.speed-prepared"),4); + } +} + diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/config/TPQueryStoreConfigBuilderTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/config/TPQueryStoreConfigBuilderTest.java new file mode 100644 index 0000000..6284979 --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/config/TPQueryStoreConfigBuilderTest.java @@ -0,0 +1,143 @@ +package net.forwardfire.tpquery.config; + +import static org.junit.Assert.assertNotNull; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.bind.JAXBException; + +import org.junit.Test; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.store.executor.TPQExecutorStatement; + +public class TPQueryStoreConfigBuilderTest { + + @Test + public void testBuildTree() throws Exception { + TPQManager manager = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:mem:test") + .createQuery("test").parseStatement("select * from table $$inc:junit.inc.test$$ $$inc:junit.inc.inc.test$$").build() + .createQuerySetTree("inc") + .setTemplate(true) + .createQuery("test") + .parseStatement("where 1=1 ") + .build() + .createQuerySet("inc") + .createQuery("test") + .parseStatement("AND 2=2") + .build() + .build() + .buildTree() + .build() + .build(); + assertNotNull(manager); + assertNotNull(manager.getQueryExecutorContext()); + assertNotNull(manager.getQueryStore().getQueryNames()); + } + + @Test(expected=IllegalStateException.class) + public void testBuildTreeInvalid() throws Exception { + TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:mem:test") + .createQuery("test").parseStatement("select * from table $$inc:junit.inc.test$$ $$inc:junit.inc.inc.test$$").build() + .createQuerySetTree("inc") + .setTemplate(true) + .createQuery("test") + .parseStatement("where 1=1 ") + .build() + .createQuerySet("inc") + .createQuery("test") + .parseStatement("AND 2=2") + .build() + .buildTree() + // buildTree() should be here + .build() + .build(); + } + + @Test + public void testParameter() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:mem:test") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a",TPQFactory.ParameterValueType.INTEGER) + .setDefaultValue("123") + .setType(TPQFactory.StatementParameter.VALUE) + .build() + .build() + .build() + .build(); + assertNotNull(store); + } + + @Test + public void testQuery() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:mem:test") + .createQuery("test") + .parseStatement("select * from table") + .setDescription("foobar") + .setTimeout(1234) + .setTemplate(false) + .setLanguage("SQL") + .build() + .build() + .build(); + assertNotNull(store); + TPQExecutorStatement q = store.getQueryExecutorContext().prepareQuery("junit.test", null); + assertNotNull(q.getName()); + assertNotNull(q.getLanguage()); + assertNotNull(q.getTimeout()); + assertNotNull(q.getStatement()); + } + + @Test + public void testReadQuerySetResource() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .readQuerySet("net/forwardfire/tpquery/test-query.xml") + .build(); + assertNotNull(store); + Map para = new HashMap<>(); + para.put("id",1); + para.put("status",123); + para.put("name","junit"); + TPQExecutorStatement q = store.getQueryExecutorContext().prepareQuery("article.insert", para); + assertNotNull(q.getName()); + } + + @Test + public void testReadQuerySetFile() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .readQuerySet(new File("./src/test/resources/net/forwardfire/tpquery/test-query.xml")) + .build(); + assertNotNull(store); + Map para = new HashMap<>(); + para.put("id",1); + para.put("status",123); + para.put("name","junit"); + TPQExecutorStatement q = store.getQueryExecutorContext().prepareQuery("article.insert", para); + assertNotNull(q.getName()); + } + + @Test(expected=JAXBException.class) + public void testReadQuerySetFileNotFound() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .readQuerySet(new File("./src/test/resources/net/forwardfire/tpquery/test-query.not-found")) + .build(); + assertNotNull(store); + TPQExecutorStatement q = store.getQueryExecutorContext().prepareQuery("article.insert", null); + assertNotNull(q.getName()); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/config/TPQueryStoreConfigTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/config/TPQueryStoreConfigTest.java new file mode 100644 index 0000000..7eb1a84 --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/config/TPQueryStoreConfigTest.java @@ -0,0 +1,246 @@ +package net.forwardfire.tpquery.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.config.TPQConfig; +import net.forwardfire.tpquery.statement.language.TPQStatementLanguageSql; +import net.forwardfire.tpquery.statement.parameter.TPQStatementParameterValue; +import net.forwardfire.tpquery.store.executor.TPQExecutorStatement; + +public class TPQueryStoreConfigTest { + + @Test() + public void testConstructors() throws Exception { + TPQConfig c0 = new TPQConfig(); + assertNotNull(c0); + assertTrue(c0.getStatementLanguages().isEmpty()); + assertTrue(c0.getStatementParameters().isEmpty()); + + TPQConfig c1 = TPQFactory.createConfig(); + assertNotNull(c1); + assertFalse(c1.getStatementLanguages().isEmpty()); + assertFalse(c1.getStatementParameters().isEmpty()); + } + + // --------- + + @Test() + public void testParameterValueScriptRemove() throws Exception { + TPQConfig c = TPQFactory.createConfig(); + c.addParameterValueScript("abc"); + c.removeParameterValueScript("abc"); + } + + // --------- + + @Test(expected=IllegalArgumentException.class) + public void testTemplateTypeAdd() throws Exception { + TPQConfig c = TPQFactory.createConfig(); + c.addStatementParameter(new TPQStatementParameterValue(TPQFactory.StatementParameter.VALUE)); + } + + @Test(expected=NullPointerException.class) + public void testTemplateTypeRemove() throws Exception { + TPQConfig c = TPQFactory.createConfig(); + c.removeStatementParameter(TPQFactory.StatementParameter.VALUE); + c.removeStatementParameter(TPQFactory.StatementParameter.VALUE); + } + + // --------- + + @Test(expected=IllegalArgumentException.class) + public void testLanguageTypeAdd() throws Exception { + TPQConfig c = TPQFactory.createConfig(); + c.addStatementLanguage(new TPQStatementLanguageSql(TPQFactory.StatementLanguage.SQL)); + } + + @Test(expected=NullPointerException.class) + public void testLanguageTypeRemove() throws Exception { + TPQConfig c = TPQFactory.createConfig(); + c.removeStatementLanguage(TPQFactory.StatementLanguage.SQL); + c.removeStatementLanguage(TPQFactory.StatementLanguage.SQL); + } + + // --------- + + @Test(expected=IllegalArgumentException.class) + public void testValueTypeAliasAdd() throws Exception { + TPQConfig c = TPQFactory.createConfig(); + c.addValueTypeAlias("key", "v0"); + c.addValueTypeAlias("key", "v1"); + } + + @Test(expected=NullPointerException.class) + public void testValueTypeAliasRemoveIllegalKey() throws Exception { + TPQConfig c = TPQFactory.createConfig(); + c.removeValueTypeAlias("unknown-key"); + } + + @Test() + public void testValueTypeAliasRemove() throws Exception { + TPQConfig c = TPQFactory.createConfig(); + c.removeValueTypeAlias(TPQFactory.ParameterValueTypeAlias.BIGINT); + } + + // --------- + + @Test(expected=NullPointerException.class) + public void testQuerySetRemoveIllegalKey() throws Exception { + TPQConfig c = TPQFactory.createConfig(); + c.removeQuerySet("unknown-key"); + } + + @Test(expected=NullPointerException.class) + public void testQuerySetRemoveNull() throws Exception { + TPQConfig c = TPQFactory.createConfig(); + c.removeQuerySet(null); + } + + @Test() + public void testQuerySetRemove() throws Exception { + TPQConfig c = TPQFactory.createConfig(); + TPQFactory + .createManagerBuilder(c) + .createQuerySet("junit", "jar:mem:test") + .setTemplate(false) + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table") + .build() + .build() + .build(); + c.removeQuerySet("jar:mem:test"); + assertTrue(c.getQuerySets().isEmpty()); + } + + // --------- + + @Test() + public void testRootTemplatePath() throws Exception { + // test config.addQuerySet where template is already set. + TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:mem:test") + .setTemplate(false) + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table") + .build() + .build() + .build(); + } + + @Test + public void testPreparedResult() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + TPQManager store = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table") + .setDescription("foobar") + .setTimeout(1234) + .build() + .build() + .build(); + assertNotNull(store); + TPQExecutorStatement q = store.getQueryExecutorContext().prepareQuery("junit.test", null); + assertNotNull(q.getName()); + assertNotNull(q.getLanguage()); + assertNotNull(q.getTimeout()); + assertNotNull(q.getStatement()); + assertNotNull(q.getParameters()); + assertNotNull(q.getProperties()); + } + + @Test + public void testSeparator() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + config.setTreePathSeperator("/"); + TPQManager store = TPQFactory.createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table") + .setDescription("foobar") + .setTimeout(1234) + .build() + .build() + .build(); + assertNotNull(store); + TPQExecutorStatement q = store.getQueryExecutorContext().prepareQuery("junit/test", null); + assertNotNull(q.getName()); + } + + @Test(expected=IllegalArgumentException.class) + public void testWrongClassParameterType() throws Exception { + TPQManager manager = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", "java.lang.StringFooBar").build() + .build() + .build() + .build(); + assertNotNull(manager); + } + + @Test + public void testDefaultParameterType() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + config.setDefaultParameterType(TPQFactory.StatementParameter.RAW); + TPQManager store = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setDefaultValue("raw").build() + .build() + .build() + .build(); + assertNotNull(store); + TPQExecutorStatement q = store.getQueryExecutorContext().prepareQuery("junit.test", null); + assertNotNull(q.getName()); + assertTrue(q.getStatement().contains("raw")); + } + + @Test + public void testCopyChild() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:mem:test") + .addQueryHint("p0", "v0") + .addQueryHint("p1", "v1") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table") + .build() + .createQuery("test-vv") + .parseStatement("select * from table") + .addQueryHint("p0", "vv") + .build() + .build() + .build(); + assertNotNull(store); + TPQExecutorStatement q = store.getQueryExecutorContext().prepareQuery("junit.test", null); + assertNotNull(q.getProperties().get("p0")); + assertEquals("v0",q.getProperties().get("p0")); + assertEquals("v1",q.getProperties().get("p1")); + + TPQExecutorStatement qvv = store.getQueryExecutorContext().prepareQuery("junit.test-vv", null); + assertNotNull(qvv.getProperties().get("p0")); + assertEquals("vv",qvv.getProperties().get("p0")); + assertEquals("v1",qvv.getProperties().get("p1")); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/config/TPQueryStoreConfigValidatorTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/config/TPQueryStoreConfigValidatorTest.java new file mode 100644 index 0000000..e24e3c1 --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/config/TPQueryStoreConfigValidatorTest.java @@ -0,0 +1,130 @@ +package net.forwardfire.tpquery.config; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.config.validate.TPQConfigValidator; +import net.forwardfire.tpquery.config.validate.TPQConfigValidatorCheck; +import net.forwardfire.tpquery.config.validate.TPQConfigValidatorCheckDescriptionNotBlank; +import net.forwardfire.tpquery.config.validate.TPQConfigValidatorCheckNamePattern; +import net.forwardfire.tpquery.config.validate.TPQConfigValidatorCheckParameterDefaultValueNotBlank; +import net.forwardfire.tpquery.config.validate.TPQConfigValidatorCheckParameterNamePattern; +import net.forwardfire.tpquery.config.validate.TPQConfigValidatorCheckParameterTypePattern; +import net.forwardfire.tpquery.config.validate.TPQConfigValidatorCheckParameterValueTypePattern; +import net.forwardfire.tpquery.model.TPQuery; + +public class TPQueryStoreConfigValidatorTest { + + @Test() + public void testPatternValidators() throws Exception { + TPQConfig config = TPQFactory + .createConfigBuilder() + .createQuerySet("junit", "jar:mem:test") + .createQuery("testCAPS").parseStatement("select * from table $$inc:junit.inc.test$$ $$inc:junit.inc.inc.test$$").build() + .createQuerySetTree("inc") + .setTemplate(true) + .createQuery("test") + .parseStatement("where a=$$a$$ ") + .createQueryParameter("a", Integer.class) + .setDefaultValue("1") + .build() + .build() + .createQuerySet("inc") + .createQuery("test") + .parseStatement("AND 2=2") + .build() + .build() + .buildTree() + .build() + .build(); + + config.addConfigValidator(".*", new TPQConfigValidatorCheckNamePattern(".*")); + config.addConfigValidator(".*", new TPQConfigValidatorCheckParameterNamePattern(".*")); + config.addConfigValidator(".*", new TPQConfigValidatorCheckParameterTypePattern(".*")); + config.addConfigValidator(".*", new TPQConfigValidatorCheckParameterValueTypePattern(".*")); + config.addConfigValidator(".*", new TPQConfigValidatorCheck() { + @Override + public void validateQuery(TPQuery query) { + } + }); + TPQManager manager = TPQFactory.createManager(config); + assertNotNull(manager); + } + + @Test(expected=IllegalArgumentException.class) + public void testDescriptionNotBlank() throws Exception { + TPQConfig config = TPQFactory + .createConfigBuilder() + .createQuerySet("junit", "jar:mem:test") + .createQuery("test-oke") + .setDescription("foobar") + .parseStatement("select * from table") + .build() + .createQuery("test-fail") + .setDescription("") + .parseStatement("select * from table") + .build() + .build() + .build(); + + TPQConfigValidator t = config.addConfigValidator("junit.test", new TPQConfigValidatorCheckDescriptionNotBlank()); + config.removeConfigValidator(t); + + config.addConfigValidator(".*", new TPQConfigValidatorCheckDescriptionNotBlank()); + TPQManager manager = TPQFactory.createManager(config); + assertNotNull(manager); + } + + @Test(expected=IllegalArgumentException.class) + public void testParameterDefaultValueNotBlank() throws Exception { + TPQConfig config = TPQFactory + .createConfigBuilder() + .createQuerySet("junit", "jar:mem:test") + .createQuery("test-oke") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.INTEGER) + .setDefaultValue("1") + .build() + .build() + .createQuery("test-fail") + .setDescription("") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.INTEGER) + .setDefaultValue("") + .build() + .build() + .build() + .build(); + config.addConfigValidator(".*", new TPQConfigValidatorCheckParameterDefaultValueNotBlank()); + TPQManager manager = TPQFactory.createManager(config); + assertNotNull(manager); + } + + @Test(expected=IllegalArgumentException.class) + public void testDisableRAWExample() throws Exception { + TPQConfig config = TPQFactory + .createConfigBuilder() + .createQuerySet("junit", "jar:mem:test") + .createQuery("test-oke") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.INTEGER) + .setType(TPQFactory.StatementParameter.RAW) + .build() + .build() + .createQuery("test-fail") + .setDescription("") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.INTEGER) + .setType(TPQFactory.StatementParameter.RAW) + .build() + .build() + .build() + .build(); + config.addConfigValidator("junit.test-f.*", new TPQConfigValidatorCheckParameterTypePattern("!RAW")); + TPQManager manager = TPQFactory.createManager(config); + assertNotNull(manager); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/executor/TQueryExecutorTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/executor/TQueryExecutorTest.java new file mode 100644 index 0000000..be8d57e --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/executor/TQueryExecutorTest.java @@ -0,0 +1,125 @@ +package net.forwardfire.tpquery.executor; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import net.forwardfire.tpquery.store.executor.AbstractTPQExecutor; +import net.forwardfire.tpquery.store.executor.TPQExecutorContext; +import net.forwardfire.tpquery.store.executor.TPQExecutorStatement; + +import org.junit.Test; + +public class TQueryExecutorTest { + + class TestExecutorConnection { + + } + + class TestExecutorStatement { + + } + + class TestExecutor extends AbstractTPQExecutor { + + public TestExecutor(TPQExecutorContext context) { + super(context); + registrateStatementCreator("SQL", (connection,statementText) -> new TestExecutorStatement()); + } + + @Override + protected int executeUpdate(TestExecutorStatement statement) { + return 0; + } + + @Override + protected void prepareParameterValue(TestExecutorStatement statement,int index, Object value) { + } + + @Override + protected void prepareTimeout(TestExecutorStatement statement,Integer timeout) { + } + } + + @Test() + public void testFactory() throws Exception { + + TestExecutor exe = new TestExecutor(new TPQExecutorContext() { + @Override + public TPQExecutorStatement prepareQuery(String queryName,Map parameters) { + return new TPQExecutorStatement() { + @Override + public Integer getTimeout() { + return null; + } + + @Override + public String getStatement() { + return "select * from table where a=?"; + } + + @Override + public Map getProperties() { + return Collections.emptyMap(); + } + + @Override + public List getParameters() { + return Arrays.asList(new Object[]{123}); + } + + @Override + public String getName() { + return "junit.test"; + } + + @Override + public String getLanguage() { + return "SQL"; + } + }; + } + }); + exe.executeUpdate(new TestExecutorConnection(), "junit.test"); + + exe = new TestExecutor(new TPQExecutorContext() { + @Override + public TPQExecutorStatement prepareQuery(String queryName,Map parameters) { + return new TPQExecutorStatement() { + @Override + public Integer getTimeout() { + return 1200; + } + + @Override + public String getStatement() { + return "select * from table"; + } + + @Override + public Map getProperties() { + return Collections.emptyMap(); + } + + @Override + public List getParameters() { + return Arrays.asList(new Object[]{123}); + } + + @Override + public String getName() { + return "junit.test-timeout"; + } + + @Override + public String getLanguage() { + return "SQL"; + } + }; + } + }); + + exe.executeUpdate(new TestExecutorConnection(), "junit.test-timeout"); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/model/TPQueryPropertyTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/model/TPQueryPropertyTest.java new file mode 100644 index 0000000..6d84cdd --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/model/TPQueryPropertyTest.java @@ -0,0 +1,32 @@ +package net.forwardfire.tpquery.model; + +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.store.executor.TPQExecutorStatement; + +public class TPQueryPropertyTest { + + @Test + public void testPropertyCopy() throws Exception { + TPQManager store = TPQFactory.createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem:test") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .addQueryHint("p0", "v0") + .createQuery("test") + .appendText("select * from foobar") + .build() + .build() + .build(); + Map para = new HashMap(); + TPQExecutorStatement prepared = store.getQueryExecutorContext().prepareQuery("junit.test", para); + assertEquals("v0",prepared.getProperties().get("p0")); + } +} + diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/model/XMLMarshallerTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/model/XMLMarshallerTest.java new file mode 100644 index 0000000..14020ba --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/model/XMLMarshallerTest.java @@ -0,0 +1,93 @@ +package net.forwardfire.tpquery.model; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +import org.junit.Test; + +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.model.TPQuerySet; +import net.forwardfire.tpquery.model.AbstractXMLMarshaller; +import net.forwardfire.tpquery.model.TPQuerySetXMLMarshaller; +import net.forwardfire.tpquery.statement.TPQStatementPartInclude; +import net.forwardfire.tpquery.statement.TPQStatementPartParameter; +import net.forwardfire.tpquery.statement.TPQStatementPartText; + +public class XMLMarshallerTest { + + private TPQuerySet createTest() throws Exception { + + TPQuerySet qs = new TPQuerySet("junit"); + qs.setLanguage("xql"); + + TPQuery ql = new TPQuery("qlimit"); + ql.setTemplate(true); + ql.setDescription("test query limit"); + ql.addQueryPart(new TPQStatementPartText(" limit=")); + ql.addQueryPart(new TPQStatementPartParameter("limit")); + ql.addQueryPart(new TPQStatementPartText(" offset=")); + ql.addQueryPart(new TPQStatementPartParameter("offset")); + + TPQueryParameter lv1 = new TPQueryParameter("limit","int"); + lv1.setDefaultValue("110"); + ql.addQueryParameter(lv1); + + TPQueryParameter lv2 = new TPQueryParameter("offset","int"); + lv2.setDefaultValue("0"); + ql.addQueryParameter(lv2); + + qs.addQuery(ql); + + TPQuery q = new TPQuery("test"); + q.setDescription("test query"); + + q.addQueryPart(new TPQStatementPartText("\n\tSELECT * FROM table tb\n\t WHERE 1=1 \n\t\t AND tb.size=")); + q.addQueryPart(new TPQStatementPartParameter("size")); + q.addQueryPart(new TPQStatementPartText("\n\t\t AND tb.status=")); + q.addQueryPart(new TPQStatementPartParameter("status")); + q.addQueryPart(new TPQStatementPartText("\n\t\t")); + q.addQueryPart(new TPQStatementPartInclude("junit.qlimit")); + q.addQueryPart(new TPQStatementPartText("\n\t")); + + TPQueryParameter pv1 = new TPQueryParameter(); + pv1.setName("size"); + pv1.setValueType(TPQFactory.ParameterValueType.INTEGER); + + TPQueryParameter pv2 = new TPQueryParameter(); + pv2.setName("status"); + pv2.setValueType(TPQFactory.ParameterValueType.STRING); + + q.addQueryParameter(pv1); + q.addQueryParameter(pv2); + + qs.addQuery(q); + return qs; + } + + @Test + public void testRoundTrip() throws Exception { + TPQuerySet qs = createTest(); + TPQuerySetXMLMarshaller xmlDriver = new TPQuerySetXMLMarshaller(); + + ByteArrayOutputStream out = new ByteArrayOutputStream(4096); + xmlDriver.marshal(qs, out); + TPQuerySet result = xmlDriver.unmarshal(new ByteArrayInputStream(out.toByteArray())); + + assertNotNull(result); + assertEquals(qs.getName(),result.getName()); + assertEquals(qs.getLanguage(),result.getLanguage()); + } + + + @Test + public void testXMLMarshallerClasses() throws Exception { + assertNotNull(new AbstractXMLMarshaller.Meta()); + assertNotNull(new AbstractXMLMarshaller.Element()); + assertNotNull(new AbstractXMLMarshaller.Attribute()); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/TPQueryStatementMarshallerAdapterTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/TPQueryStatementMarshallerAdapterTest.java new file mode 100644 index 0000000..2de6889 --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/TPQueryStatementMarshallerAdapterTest.java @@ -0,0 +1,27 @@ +package net.forwardfire.tpquery.statement; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import net.forwardfire.tpquery.statement.TPQStatementMarshallerAdapter; + +import org.junit.Test; + + +public class TPQueryStatementMarshallerAdapterTest { + + @Test + public void testMarshalNull() throws Exception { + TPQStatementMarshallerAdapter adapter = new TPQStatementMarshallerAdapter(); + assertNotNull(adapter.marshal(null)); + assertTrue(adapter.marshal(null).isEmpty()); + } + + @Test + public void testUnmarshalNull() throws Exception { + TPQStatementMarshallerAdapter adapter = new TPQStatementMarshallerAdapter(); + assertNotNull(adapter.unmarshal(null)); + assertTrue(adapter.unmarshal(null).isEmpty()); + assertNotNull(adapter.unmarshal("")); + assertTrue(adapter.unmarshal("").isEmpty()); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/TPQueryStatementMarshallerTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/TPQueryStatementMarshallerTest.java new file mode 100644 index 0000000..199af03 --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/TPQueryStatementMarshallerTest.java @@ -0,0 +1,108 @@ +package net.forwardfire.tpquery.statement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import net.forwardfire.tpquery.statement.TPQStatement; +import net.forwardfire.tpquery.statement.TPQStatementMarshaller; +import net.forwardfire.tpquery.statement.TPQStatementPartInclude; +import net.forwardfire.tpquery.statement.TPQStatementPartParameter; +import net.forwardfire.tpquery.statement.TPQStatementPartText; + +import org.junit.Test; + +public class TPQueryStatementMarshallerTest { + + @Test(expected=NullPointerException.class) + public void testParseNull() throws Exception { + TPQStatementMarshaller parser = new TPQStatementMarshaller(); + parser.unmarshal(null); + } + + @Test() + public void testParseEmpty() throws Exception { + TPQStatementMarshaller parser = new TPQStatementMarshaller(); + List result = parser.unmarshal(""); + assertNotNull(result); + assertTrue(result.isEmpty()); + } + + @Test() + public void testParseText() throws Exception { + TPQStatementMarshaller parser = new TPQStatementMarshaller(); + List result = parser.unmarshal("foobar"); + assertNotNull(result); + assertFalse(result.isEmpty()); + assertTrue(result.size()==1); + assertNotNull(result.get(0)); + assertTrue(result.get(0) instanceof TPQStatementPartText); + } + + @Test() + public void testParseTemplate() throws Exception { + TPQStatementMarshaller parser = new TPQStatementMarshaller(); + List result = parser.unmarshal("$$foobar$$"); + assertNotNull(result); + assertFalse(result.isEmpty()); + assertTrue(result.size()==1); + assertNotNull(result.get(0)); + assertTrue(result.get(0) instanceof TPQStatementPartParameter); + } + + @Test(expected=IllegalArgumentException.class) + public void testParseTemplateNoEnd() throws Exception { + new TPQStatementMarshaller().unmarshal("$$foobar"); + } + + @Test(expected=IllegalArgumentException.class) + public void testParseTemplateEmpty() throws Exception { + new TPQStatementMarshaller().unmarshal("$$$$"); + } + + @Test() + public void testParseTemplateInclude() throws Exception { + TPQStatementMarshaller parser = new TPQStatementMarshaller(); + List result = parser.unmarshal("$$inc:foobar$$"); + assertNotNull(result); + assertFalse(result.isEmpty()); + assertTrue(result.size()==1); + assertNotNull(result.get(0)); + assertTrue(result.get(0) instanceof TPQStatementPartInclude); + } + + + + @Test(expected=NullPointerException.class) + public void testPrintNull() throws Exception { + TPQStatementMarshaller parser = new TPQStatementMarshaller(); + parser.marshal(null); + } + + @Test() + public void testPrintEmpty() throws Exception { + List data = new ArrayList<>(); + TPQStatementMarshaller parser = new TPQStatementMarshaller(); + String result = parser.marshal(data); + assertNotNull(result); + assertTrue(result.isEmpty()); + } + + @Test() + public void testPrintText() throws Exception { + List data = new ArrayList<>(); + data.add(new TPQStatementPartText("p0")); + data.add(new TPQStatementPartText("p1")); + data.add(new TPQStatementPartText("p2")); + TPQStatementMarshaller parser = new TPQStatementMarshaller(); + String result = parser.marshal(data); + assertNotNull(result); + assertFalse(result.isEmpty()); + assertEquals("p0p1p2",result); + } +} + diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/TPQueryStatementPartIncludeTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/TPQueryStatementPartIncludeTest.java new file mode 100644 index 0000000..15265b9 --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/TPQueryStatementPartIncludeTest.java @@ -0,0 +1,61 @@ +package net.forwardfire.tpquery.statement; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.store.executor.TPQExecutorStatement; + +import org.junit.Test; + +public class TPQueryStatementPartIncludeTest { + + @Test(expected=NullPointerException.class) + public void testFailInclude() throws Exception { + TPQFactory.createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem:test") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("include-missing") + .appendText("select * from foobar") + .appendInclude("include-missing-query") + .build() + .build() + .build(); + } + + @Test + public void testIncludeMultple() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .readQuerySet("net/forwardfire/tpquery/test-include-multiple.xml") + .build(); + TPQExecutorStatement q = store.getQueryExecutorContext().prepareQuery("test.multipleInclude", null); + assertNotNull(q.getName()); + assertTrue(q.getStatement().contains("price_list")); + assertTrue(q.getStatement().contains("key='stats_correction') AS mrt")); + } + + @Test(expected=IllegalArgumentException.class) + public void testIncludeLoop() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .readQuerySet("net/forwardfire/tpquery/test-include-loop.xml") + .build(); + store.getQueryExecutorContext().prepareQuery("test.loopInclude", null); + } + + @Test(expected=IllegalArgumentException.class) + public void testQueryChecked() throws Exception { + TPQFactory.createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem:test") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("test") + .appendText("select * from foobar") + .build() + .createQuery("test-fail") + .appendInclude("junit.test") + .build() + .build() + .build(); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/TPQueryStatementWriterTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/TPQueryStatementWriterTest.java new file mode 100644 index 0000000..371efbf --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/TPQueryStatementWriterTest.java @@ -0,0 +1,79 @@ +package net.forwardfire.tpquery.statement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.HashMap; +import java.util.Map; + +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.config.TPQConfig; +import net.forwardfire.tpquery.statement.TPQStatementWriter; +import net.forwardfire.tpquery.statement.language.AbstractTPQStatementLanguage; +import net.forwardfire.tpquery.statement.language.TPQStatementLanguageSql; +import net.forwardfire.tpquery.store.executor.TPQExecutorStatement; + +import org.junit.Test; + +public class TPQueryStatementWriterTest { + + private TPQStatementWriter createWriter() { + Map para = new HashMap<>(); + TPQStatementLanguageSql language = new TPQStatementLanguageSql(TPQFactory.StatementLanguage.SQL); + TPQStatementWriter writer = language.createQueryWriter(para); + return writer; + } + + @Test + public void testWriterNull() throws Exception { + TPQStatementWriter writer = createWriter(); + assertNotNull(writer); + assertNotNull(writer.getQueryText()); + assertNotNull(writer.getQueryParameterMapping()); + } + + @Test + public void testWriterAppend() throws Exception { + TPQStatementWriter writer = createWriter(); + assertNotNull(writer); + + writer.appendQueryText("t0"); + writer.appendQueryText("t1"); + writer.appendQueryText("t2"); + assertEquals("t0t1t2",writer.getQueryText()); + } + + @Test() + public void testWriterNoneMapped() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + config.addStatementLanguage(new AbstractTPQStatementLanguage("foobar") { + @Override + public TPQStatementWriter createQueryWriter(Map parameterData) { + return new AbstractTPQStatementWriter(parameterData) { + @Override + public boolean isValueMappedWriter() { + return false; + } + }; + } + }); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("foobar") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setDefaultValue("a").build() + .build() + .build() + .build(); + TPQExecutorStatement s1 = queryManager.getQueryExecutorContext().prepareQuery("junit.test", null); + assertEquals("foobar",s1.getLanguage()); + + // run twice to test also the prepareParameters without cacheKey generation. + TPQExecutorStatement s2 = queryManager.getQueryExecutorContext().prepareQuery("junit.test", null); + assertEquals("foobar",s2.getLanguage()); + } +} + diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguageHqlTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguageHqlTest.java new file mode 100644 index 0000000..c450ecb --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguageHqlTest.java @@ -0,0 +1,54 @@ +package net.forwardfire.tpquery.statement.language; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.statement.TPQStatementWriter; +import net.forwardfire.tpquery.statement.language.TPQStatementLanguageHql; +import net.forwardfire.tpquery.store.TPQueryStoreStatementMapper; + +import org.junit.Test; + +public class TPQStatementLanguageHqlTest { + + private TPQStatementWriter createWriter() { + Map para = new HashMap<>(); + TPQStatementLanguageHql language = new TPQStatementLanguageHql(TPQFactory.StatementLanguage.HQL); + TPQStatementWriter writer = language.createQueryWriter(para); + return writer; + } + + @SuppressWarnings("serial") + @Test + public void testPreparedParameters() throws Exception { + TPQStatementWriter writer = createWriter(); + assertNotNull(writer); + + writer.appendQueryText("select * from foobar where a="); + writer.appendQueryParameter(new TPQueryStoreStatementMapper() { + @Override + public Object getParameterValue(Map parameters) { + return "123"; + } + }); + writer.appendQueryText(" and b="); + writer.appendQueryParameter(new TPQueryStoreStatementMapper() { + @Override + public Object getParameterValue(Map parameters) { + return "456"; + } + }); + + assertFalse(writer.getQueryParameterMapping().isEmpty()); + assertTrue(writer.getQueryParameterMapping().size()==2); + assertEquals("select * from foobar where a=?1 and b=?2",writer.getQueryText()); + assertEquals("123",writer.getQueryParameterMapping().get(0).getParameterValue(null)); + assertEquals("456",writer.getQueryParameterMapping().get(1).getParameterValue(null)); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguageSqlTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguageSqlTest.java new file mode 100644 index 0000000..f9dba00 --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/language/TPQStatementLanguageSqlTest.java @@ -0,0 +1,48 @@ +package net.forwardfire.tpquery.statement.language; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.statement.TPQStatementWriter; +import net.forwardfire.tpquery.statement.language.TPQStatementLanguageSql; +import net.forwardfire.tpquery.store.TPQueryStoreStatementMapper; + +public class TPQStatementLanguageSqlTest { + + private TPQStatementWriter createWriter() { + Map para = new HashMap<>(); + TPQStatementLanguageSql language = new TPQStatementLanguageSql(TPQFactory.StatementLanguage.SQL); + TPQStatementWriter writer = language.createQueryWriter(para); + return writer; + } + + @SuppressWarnings("serial") + @Test + public void testPreparedParameters() throws Exception { + TPQStatementWriter writer = createWriter(); + assertNotNull(writer); + + writer.appendQueryText("select * from foobar where a="); + writer.appendQueryParameter(new TPQueryStoreStatementMapper() { + @Override + public Object getParameterValue(Map parameters) { + return "123"; + } + }); + writer.appendQueryText(" and b="); + writer.appendQueryParameter(new TPQueryStoreStatementMapper() { + @Override + public Object getParameterValue(Map parameters) { + return "456"; + } + }); + + assertEquals("select * from foobar where a=? and b=?",writer.getQueryText()); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/parameter/TPQueryParameterDefaultValueTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/parameter/TPQueryParameterDefaultValueTest.java new file mode 100644 index 0000000..9669c6b --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/parameter/TPQueryParameterDefaultValueTest.java @@ -0,0 +1,140 @@ +package net.forwardfire.tpquery.statement.parameter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.config.TPQConfig; +import net.forwardfire.tpquery.store.executor.TPQExecutorStatement; + +import org.junit.Test; + +public class TPQueryParameterDefaultValueTest { + + @Test() + public void testRawString() throws Exception { + TPQConfig config = TPQFactory + .createConfigBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("test") + .parseStatement("select * from foobar where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING) + .setType(TPQFactory.StatementParameter.RAW) + .setDefaultValue("abc") + .build() + .build() + .build() + .build(); + TPQManager manager = TPQFactory.createManager(config); + Map para = new HashMap(); + TPQExecutorStatement prepared = manager.getQueryExecutorContext().prepareQuery("junit.test", para); + assertTrue(prepared.getStatement().contains("=abc")); + } + + @Test() + public void testEpoch() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("test") + .parseStatement("select * from foobar where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.LONG) + .setDefaultValue("js:epoch()") + .build() + .build() + .build() + .build(); + Map para = new HashMap(); + TPQExecutorStatement prepared = store.getQueryExecutorContext().prepareQuery("junit.test", para); + assertTrue(!prepared.getParameters().isEmpty()); + assertTrue(prepared.getParameters().get(0) != null); + assertTrue(prepared.getParameters().get(0) instanceof Long); + } + + @Test() + public void testTime() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("test") + .parseStatement("select * from foobar where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.SQL_TIME) + .setDefaultValue("js:time()") + .build() + .build() + .build() + .build(); + Map para = new HashMap(); + TPQExecutorStatement prepared = store.getQueryExecutorContext().prepareQuery("junit.test", para); + assertTrue(!prepared.getParameters().isEmpty()); + assertTrue(prepared.getParameters().get(0) != null); + assertTrue(prepared.getParameters().get(0) instanceof java.sql.Time); + } + + @Test() + public void testCreateObjectConstructorAutoType() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("test") + .parseStatement("select * from foobar where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING) + .setDefaultValue("js:createObject(java.lang.String,'foobar')") + .build() + .build() + .build() + .build(); + Map para = new HashMap(); + TPQExecutorStatement prepared = store.getQueryExecutorContext().prepareQuery("junit.test", para); + assertTrue(!prepared.getParameters().isEmpty()); + assertTrue(prepared.getParameters().get(0) != null); + assertTrue(prepared.getParameters().get(0) instanceof String); + assertEquals("foobar",prepared.getParameters().get(0)); + } + + @Test() + public void testCreateObjectConstructorNoArguments() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("test") + .parseStatement("select * from foobar where a=$$a$$") + .createQueryParameter("a", "java.util.Date") + .setDefaultValue("js:createObject(java.util.Date)") + .build() + .build() + .build() + .build(); + Map para = new HashMap(); + TPQExecutorStatement prepared = store.getQueryExecutorContext().prepareQuery("junit.test", para); + assertTrue(!prepared.getParameters().isEmpty()); + assertTrue(prepared.getParameters().get(0) != null); + assertTrue(prepared.getParameters().get(0) instanceof java.util.Date); + } + + @Test(expected=Exception.class) + public void testCreateObjectConstructorWrongClass() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("test") + .parseStatement("select * from foobar where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.SQL_TIME) + .setDefaultValue("js:createObject(java.lang.StringNotFound,'foobar')") + .build() + .build() + .build() + .build(); + store.getQueryExecutorContext().prepareQuery("junit.test", new HashMap()); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/parameter/TPQueryParameterTypeListTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/parameter/TPQueryParameterTypeListTest.java new file mode 100644 index 0000000..e571b1f --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/parameter/TPQueryParameterTypeListTest.java @@ -0,0 +1,263 @@ +package net.forwardfire.tpquery.statement.parameter; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.model.TPQuerySet; +import net.forwardfire.tpquery.statement.TPQStatementPartParameter; +import net.forwardfire.tpquery.store.executor.TPQExecutorStatement; + +public class TPQueryParameterTypeListTest { + + @Test(expected=NullPointerException.class) + public void testNullValue() throws Exception { + TPQuery q = new TPQuery(); + q.setName("test"); + q.addQueryPart(new TPQStatementPartParameter("param")); + TPQueryParameter qp = new TPQueryParameter(); + qp.setType(TPQFactory.StatementParameter.LIST); + qp.setName("param"); + //qp.setDefaultValue("1,2,3"); + qp.setValueType(TPQFactory.ParameterValueType.INTEGER); + q.addQueryParameter(qp); + + TPQuerySet qs = new TPQuerySet("junit"); + qs.setLanguage(TPQFactory.StatementLanguage.SQL); + qs.addQuery(q); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:test",qs).build(); + + Map para = new HashMap(); + store.getQueryExecutorContext().prepareQuery("junit.test", para); + } + + @Test(expected=IllegalArgumentException.class) + public void testEmptyValue() throws Exception { + TPQuery q = new TPQuery(); + q.setName("test"); + q.addQueryPart(new TPQStatementPartParameter("param")); + TPQueryParameter qp = new TPQueryParameter(); + qp.setType(TPQFactory.StatementParameter.LIST); + qp.setName("param"); + qp.setValueType(TPQFactory.ParameterValueType.INTEGER); + q.addQueryParameter(qp); + + TPQuerySet qs = new TPQuerySet("junit"); + qs.setLanguage(TPQFactory.StatementLanguage.SQL); + qs.addQuery(q); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:test",qs).build(); + + Map para = new HashMap(); + para.put("param", new ArrayList()); + store.getQueryExecutorContext().prepareQuery("junit.test", para); + } + + @Test(expected=IllegalArgumentException.class) + public void testWrongValue() throws Exception { + TPQuery q = new TPQuery(); + q.setName("test"); + q.addQueryPart(new TPQStatementPartParameter("param")); + TPQueryParameter qp = new TPQueryParameter(); + qp.setType(TPQFactory.StatementParameter.LIST); + qp.setName("param"); + qp.setValueType(TPQFactory.ParameterValueType.INTEGER); + q.addQueryParameter(qp); + + TPQuerySet qs = new TPQuerySet("junit"); + qs.setLanguage(TPQFactory.StatementLanguage.SQL); + qs.addQuery(q); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:test",qs).build(); + + Map para = new HashMap(); + para.put("param", new HashMap()); + store.getQueryExecutorContext().prepareQuery("junit.test", para); + } + + @Test() + public void testTypeListStringDefault() throws Exception { + TPQuery q = new TPQuery(); + q.setName("test"); + q.addQueryPart(new TPQStatementPartParameter("param")); + TPQueryParameter qp = new TPQueryParameter(); + qp.setType(TPQFactory.StatementParameter.LIST); + qp.setName("param"); + qp.setDefaultValue("1,2,3"); + qp.setValueType(TPQFactory.ParameterValueType.INTEGER); + q.addQueryParameter(qp); + + TPQuerySet qs = new TPQuerySet("junit"); + qs.setLanguage(TPQFactory.StatementLanguage.SQL); + qs.addQuery(q); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:mem:test",qs).build(); + + Map paraDefault = new HashMap(); + Map paraValue = new HashMap(); + paraValue.put("param", Arrays.asList(new Integer[]{1,2,3,4,5,6})); + TPQExecutorStatement queryPreparedDefault = store.getQueryExecutorContext().prepareQuery("junit.test", paraDefault); + TPQExecutorStatement queryPreparedValue = store.getQueryExecutorContext().prepareQuery("junit.test", paraValue); + + assertEquals("?,?,?",queryPreparedDefault.getStatement()); + assertEquals(3,queryPreparedDefault.getParameters().size()); + assertEquals(1,queryPreparedDefault.getParameters().get(0)); + assertEquals(2,queryPreparedDefault.getParameters().get(1)); + assertEquals(3,queryPreparedDefault.getParameters().get(2)); + + assertEquals("?,?,?,?,?,?",queryPreparedValue.getStatement()); + assertEquals(6,queryPreparedValue.getParameters().size()); + assertEquals(1,queryPreparedValue.getParameters().get(0)); + assertEquals(2,queryPreparedValue.getParameters().get(1)); + assertEquals(3,queryPreparedValue.getParameters().get(2)); + assertEquals(4,queryPreparedValue.getParameters().get(3)); + assertEquals(5,queryPreparedValue.getParameters().get(4)); + assertEquals(6,queryPreparedValue.getParameters().get(5)); + } + + @Test() + public void testTypeListValueString() throws Exception { + TPQuery q = new TPQuery(); + q.setName("test"); + q.addQueryPart(new TPQStatementPartParameter("param")); + TPQueryParameter qp = new TPQueryParameter(); + qp.setType(TPQFactory.StatementParameter.LIST); + qp.setName("param"); + qp.setDefaultValue("1,2,3"); + qp.setValueType(TPQFactory.ParameterValueType.STRING); + q.addQueryParameter(qp); + TPQuerySet qs = new TPQuerySet("junit"); + qs.setLanguage(TPQFactory.StatementLanguage.SQL); + qs.addQuery(q); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:mem:test",qs).build(); + store.getQueryExecutorContext().prepareQuery("junit.test", null); + + List valueList = new ArrayList(); + valueList.add("1"); + valueList.add("2"); + valueList.add("3"); + valueList.add("4"); + valueList.add("5"); + valueList.add("6"); + + Map paraDefault = new HashMap(); + Map paraValue = new HashMap(); + paraValue.put("param", valueList); + TPQExecutorStatement queryPreparedDefault = store.getQueryExecutorContext().prepareQuery("junit.test", paraDefault); + TPQExecutorStatement queryPreparedValue = store.getQueryExecutorContext().prepareQuery("junit.test", paraValue); + + assertEquals("?,?,?",queryPreparedDefault.getStatement()); + assertEquals(3,queryPreparedDefault.getParameters().size()); + assertEquals("1",queryPreparedDefault.getParameters().get(0)); + assertEquals("2",queryPreparedDefault.getParameters().get(1)); + assertEquals("3",queryPreparedDefault.getParameters().get(2)); + + assertEquals("?,?,?,?,?,?",queryPreparedValue.getStatement()); + assertEquals(6,queryPreparedValue.getParameters().size()); + assertEquals("1",queryPreparedValue.getParameters().get(0)); + assertEquals("2",queryPreparedValue.getParameters().get(1)); + assertEquals("3",queryPreparedValue.getParameters().get(2)); + assertEquals("4",queryPreparedValue.getParameters().get(3)); + assertEquals("5",queryPreparedValue.getParameters().get(4)); + assertEquals("6",queryPreparedValue.getParameters().get(5)); + } + + @Test() + public void testTypeListValueStringHQL() throws Exception { + TPQuery q = new TPQuery(); + q.setName("test"); + q.addQueryPart(new TPQStatementPartParameter("param")); + TPQueryParameter qp = new TPQueryParameter(); + qp.setType(TPQFactory.StatementParameter.LIST); + qp.setName("param"); + qp.setDefaultValue("1,2,3"); + qp.setValueType(TPQFactory.ParameterValueType.STRING); + q.addQueryParameter(qp); + TPQuerySet qs = new TPQuerySet("junit"); + qs.setLanguage(TPQFactory.StatementLanguage.HQL); + qs.addQuery(q); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:mem:test",qs).build(); + + List valueList = new ArrayList(); + valueList.add("1"); + valueList.add("2"); + valueList.add("3"); + valueList.add("4"); + valueList.add("5"); + valueList.add("6"); + + Map paraDefault = new HashMap(); + Map paraValue = new HashMap(); + paraValue.put("param", valueList); + TPQExecutorStatement queryPreparedDefault = store.getQueryExecutorContext().prepareQuery("junit.test", paraDefault); + TPQExecutorStatement queryPreparedValue = store.getQueryExecutorContext().prepareQuery("junit.test", paraValue); + + assertEquals("?1,?2,?3",queryPreparedDefault.getStatement()); + assertEquals(3,queryPreparedDefault.getParameters().size()); + assertEquals("1",queryPreparedDefault.getParameters().get(0)); + assertEquals("2",queryPreparedDefault.getParameters().get(1)); + assertEquals("3",queryPreparedDefault.getParameters().get(2)); + + assertEquals("?1,?2,?3,?4,?5,?6",queryPreparedValue.getStatement()); + assertEquals(6,queryPreparedValue.getParameters().size()); + assertEquals("1",queryPreparedValue.getParameters().get(0)); + assertEquals("2",queryPreparedValue.getParameters().get(1)); + assertEquals("3",queryPreparedValue.getParameters().get(2)); + assertEquals("4",queryPreparedValue.getParameters().get(3)); + assertEquals("5",queryPreparedValue.getParameters().get(4)); + assertEquals("6",queryPreparedValue.getParameters().get(5)); + } + + @Test() + public void testTypeListValueInteger() throws Exception { + TPQuery q = new TPQuery(); + q.setName("test"); + q.addQueryPart(new TPQStatementPartParameter("param")); + TPQueryParameter qp = new TPQueryParameter(); + qp.setType(TPQFactory.StatementParameter.LIST); + qp.setName("param"); + qp.setDefaultValue("1,2,3"); + qp.setValueType(TPQFactory.ParameterValueType.INTEGER); + q.addQueryParameter(qp); + TPQuerySet qs = new TPQuerySet("junit"); + qs.setLanguage(TPQFactory.StatementLanguage.SQL); + qs.addQuery(q); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:mem:test",qs).build(); + + List valueList = new ArrayList(); + valueList.add(1); + valueList.add(2); + valueList.add(3); + valueList.add(4); + valueList.add(5); + valueList.add(6); + + Map paraDefault = new HashMap(); + Map paraValue = new HashMap(); + paraValue.put("param", valueList); + TPQExecutorStatement queryPreparedDefault = store.getQueryExecutorContext().prepareQuery("junit.test", paraDefault); + TPQExecutorStatement queryPreparedValue = store.getQueryExecutorContext().prepareQuery("junit.test", paraValue); + + assertEquals("?,?,?",queryPreparedDefault.getStatement()); + assertEquals(3,queryPreparedDefault.getParameters().size()); + assertEquals(1,queryPreparedDefault.getParameters().get(0)); + assertEquals(2,queryPreparedDefault.getParameters().get(1)); + assertEquals(3,queryPreparedDefault.getParameters().get(2)); + + assertEquals("?,?,?,?,?,?",queryPreparedValue.getStatement()); + assertEquals(6,queryPreparedValue.getParameters().size()); + assertEquals(1,queryPreparedValue.getParameters().get(0)); + assertEquals(2,queryPreparedValue.getParameters().get(1)); + assertEquals(3,queryPreparedValue.getParameters().get(2)); + assertEquals(4,queryPreparedValue.getParameters().get(3)); + assertEquals(5,queryPreparedValue.getParameters().get(4)); + assertEquals(6,queryPreparedValue.getParameters().get(5)); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/parameter/TPQueryParameterTypeRawTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/parameter/TPQueryParameterTypeRawTest.java new file mode 100644 index 0000000..62aec26 --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/parameter/TPQueryParameterTypeRawTest.java @@ -0,0 +1,84 @@ +package net.forwardfire.tpquery.statement.parameter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.model.TPQuerySet; +import net.forwardfire.tpquery.statement.TPQStatementPartParameter; +import net.forwardfire.tpquery.store.executor.TPQExecutorStatement; + +public class TPQueryParameterTypeRawTest { + + @Test() + public void testTypeRaw() throws Exception { + TPQuery q = new TPQuery(); + q.setName("test"); + q.addQueryPart(new TPQStatementPartParameter("param")); + TPQueryParameter qp = new TPQueryParameter(); + qp.setType("RAW"); + qp.setName("param"); + qp.setDefaultValue("default"); + qp.setValueType(TPQFactory.ParameterValueType.STRING); + q.addQueryParameter(qp); + + TPQuerySet qs = new TPQuerySet("junit"); + qs.setLanguage(TPQFactory.StatementLanguage.SQL); + qs.addQuery(q); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:mem:test",qs).build(); + + Map paraDefault = new HashMap(); + Map paraValue = new HashMap(); + paraValue.put("param", "test"); + TPQExecutorStatement queryPreparedDefault = store.getQueryExecutorContext().prepareQuery("junit.test", paraDefault); + TPQExecutorStatement queryPreparedValue = store.getQueryExecutorContext().prepareQuery("junit.test", paraValue); + + assertEquals("default",queryPreparedDefault.getStatement()); + assertEquals(0,queryPreparedDefault.getParameters().size()); + + assertEquals("test",queryPreparedValue.getStatement()); + assertEquals(0,queryPreparedValue.getParameters().size()); + } + + @Test() + public void testTypeRawNull() throws Exception { + TPQManager store = TPQFactory.createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem:test") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("test") + .appendText("select * from foobar where 1=1 AND ") + .appendParameter("param-raw") + .appendParameter("param-raw-null") + .createQueryParameter("param-raw",String.class) + .setType(TPQFactory.StatementParameter.RAW) + .setNullable(true) + .build() + .createQueryParameter("param-raw-null",String.class) + .setType(TPQFactory.StatementParameter.RAW_NULL) + .setNullable(true) + .build() + .build() + .build() + .build(); + + Map paraValue = new HashMap(); + paraValue.put("param-raw", "raw=123"); + paraValue.put("param-raw-null", "raw-null=456"); + TPQExecutorStatement queryPreparedValue = store.getQueryExecutorContext().prepareQuery("junit.test", paraValue); + TPQExecutorStatement queryPreparedNull = store.getQueryExecutorContext().prepareQuery("junit.test", null); + + assertTrue(queryPreparedValue.getStatement().contains("raw=123")); + assertTrue(queryPreparedValue.getStatement().contains("raw-null=456")); + assertFalse(queryPreparedNull.getStatement().contains("raw=123")); + assertTrue(queryPreparedNull.getStatement().contains("null")); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/parameter/TPQueryParameterTypeValueTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/parameter/TPQueryParameterTypeValueTest.java new file mode 100644 index 0000000..e68b2f6 --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/statement/parameter/TPQueryParameterTypeValueTest.java @@ -0,0 +1,135 @@ +package net.forwardfire.tpquery.statement.parameter; + +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.model.TPQuery; +import net.forwardfire.tpquery.model.TPQueryParameter; +import net.forwardfire.tpquery.model.TPQuerySet; +import net.forwardfire.tpquery.statement.TPQStatementPartParameter; +import net.forwardfire.tpquery.store.executor.TPQExecutorStatement; + +public class TPQueryParameterTypeValueTest { + + @Test(expected=NullPointerException.class) + public void testMissingParameter() throws Exception { + TPQuery q = new TPQuery(); + q.setName("test"); + q.addQueryPart(new TPQStatementPartParameter("missing-param")); + + TPQuerySet qs = new TPQuerySet("junit"); + qs.addQuery(q); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:mem:testMissingParameter",qs).build(); + store.getQueryExecutorContext().prepareQuery("junit.test", null); + } + + @Test(expected=IllegalArgumentException.class) + public void testTypeParamWrongType() throws Exception { + TPQuery q = new TPQuery(); + q.setName("test"); + q.addQueryPart(new TPQStatementPartParameter("param")); + TPQueryParameter qp = new TPQueryParameter(); + qp.setType(TPQFactory.StatementParameter.VALUE); + qp.setName("param"); + qp.setValueType(TPQFactory.ParameterValueType.INTEGER); + q.addQueryParameter(qp); + TPQuerySet qs = new TPQuerySet("junit"); + qs.setLanguage(TPQFactory.StatementLanguage.SQL); + qs.addQuery(q); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:mem:test",qs).build(); + + Map paraValue = new HashMap(); + paraValue.put("param", "test"); + store.getQueryExecutorContext().prepareQuery("junit.test", paraValue); + } + + @Test() + public void testValidateNullParameter() throws Exception { + TPQuery q = new TPQuery(); + q.setLanguage("SQL"); + q.setName("test"); + + TPQStatementPartParameter param = new TPQStatementPartParameter("param"); + q.addQueryPart(param); + TPQueryParameter qp = new TPQueryParameter(); + qp.setType(TPQFactory.StatementParameter.VALUE); + qp.setName("param"); + qp.setValueType(TPQFactory.ParameterValueType.INTEGER); + qp.setNullable(true); + q.addQueryParameter(qp); + + TPQuerySet qs = new TPQuerySet("junit"); + qs.addQuery(q); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:mem:test",qs).build(); + store.getQueryExecutorContext().prepareQuery("junit.test", null); + } + + @Test() + public void testTypeParam() throws Exception { + TPQuery q = new TPQuery(); + q.setName("test"); + q.addQueryPart(new TPQStatementPartParameter("param")); + TPQueryParameter qp = new TPQueryParameter(); + qp.setType(TPQFactory.StatementParameter.VALUE); + qp.setName("param"); + qp.setDefaultValue("default"); + qp.setValueType(TPQFactory.ParameterValueType.STRING); + q.addQueryParameter(qp); + TPQuerySet qs = new TPQuerySet("junit"); + qs.setLanguage(TPQFactory.StatementLanguage.SQL); + qs.addQuery(q); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:mem:test",qs).build(); + + Map paraDefault = new HashMap(); + Map paraValue = new HashMap(); + paraValue.put("param", "test"); + TPQExecutorStatement queryPreparedDefault = store.getQueryExecutorContext().prepareQuery("junit.test", paraDefault); + TPQExecutorStatement queryPreparedValue = store.getQueryExecutorContext().prepareQuery("junit.test", paraValue); + + assertEquals("?",queryPreparedDefault.getStatement()); + assertEquals(1,queryPreparedDefault.getParameters().size()); + assertEquals("default",queryPreparedDefault.getParameters().get(0)); + + assertEquals("?",queryPreparedValue.getStatement()); + assertEquals(1,queryPreparedValue.getParameters().size()); + assertEquals("test",queryPreparedValue.getParameters().get(0)); + } + + @Test() + public void testTypeParamHQL() throws Exception { + TPQuery q = new TPQuery(); + q.setName("test"); + q.addQueryPart(new TPQStatementPartParameter("param")); + TPQueryParameter qp = new TPQueryParameter(); + qp.setType("VALUE"); + qp.setName("param"); + qp.setDefaultValue("default"); + qp.setValueType(TPQFactory.ParameterValueType.STRING); + q.addQueryParameter(qp); + + TPQuerySet qs = new TPQuerySet("junit"); + qs.addQuery(q); + qs.setLanguage(TPQFactory.StatementLanguage.HQL); + TPQManager store = TPQFactory.createManagerBuilder().addQuerySet("jar:junit:mem:test",qs).build(); + + Map paraDefault = new HashMap(); + Map paraValue = new HashMap(); + paraValue.put("param", "test"); + TPQExecutorStatement queryPreparedDefault = store.getQueryExecutorContext().prepareQuery("junit.test", paraDefault); + TPQExecutorStatement queryPreparedValue = store.getQueryExecutorContext().prepareQuery("junit.test", paraValue); + + assertEquals("?1",queryPreparedDefault.getStatement()); + assertEquals(1,queryPreparedDefault.getParameters().size()); + assertEquals("default",queryPreparedDefault.getParameters().get(0)); + + assertEquals("?1",queryPreparedValue.getStatement()); + assertEquals(1,queryPreparedValue.getParameters().size()); + assertEquals("test",queryPreparedValue.getParameters().get(0)); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/store/TPQueryStoreTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/store/TPQueryStoreTest.java new file mode 100644 index 0000000..200e124 --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/store/TPQueryStoreTest.java @@ -0,0 +1,139 @@ +package net.forwardfire.tpquery.store; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.Map; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.config.TPQConfig; + +import org.junit.Test; + +public class TPQueryStoreTest { + + @Test + public void testQueryStoreNames() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + config.setDefaultParameterType(TPQFactory.StatementParameter.RAW); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setDefaultValue("a").build() + .build() + .build() + .build(); + assertNotNull(queryManager.getQueryStore()); + assertNotNull(queryManager.getQueryStore().getQueryNames()); + assertTrue(queryManager.getQueryStore().getQueryNames().size() == 1); + assertEquals("junit.test",queryManager.getQueryStore().getQueryNames().get(0)); + } + + @Test + public void testQueryStoreParameters() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + config.setDefaultParameterType(TPQFactory.StatementParameter.RAW); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.INTEGER).setDefaultValue("a").build() + .build() + .build() + .build(); + + Map paraMap = queryManager.getQueryStore().getParameterMetaData("junit.test"); + assertNotNull(paraMap); + assertEquals(1,paraMap.size()); + + TPQueryParameterMetaData paraInfo = paraMap.get("a"); + assertNotNull(paraInfo); + assertEquals("a",paraInfo.getName()); + assertEquals("java.lang.Integer",paraInfo.getValueType().getName()); + } + + @Test + public void testQueryStoreIncludeParameters() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + config.setDefaultParameterType(TPQFactory.StatementParameter.RAW); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("$$inc:junit.test-inc$$") + .build() + .createQuery("test-inc") + .setTemplate(true) + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.INTEGER).setDefaultValue("a").build() + .build() + .build() + .build(); + + Map paraMap = queryManager.getQueryStore().getParameterMetaData("junit.test"); + assertNotNull(paraMap); + assertEquals(1,paraMap.size()); + + TPQueryParameterMetaData paraInfo = paraMap.get("a"); + assertNotNull(paraInfo); + assertEquals("a",paraInfo.getName()); + assertEquals("java.lang.Integer",paraInfo.getValueType().getName()); + } + + + @Test + public void testQueryStoreIncludeMultpleParameters() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + config.setDefaultParameterType(TPQFactory.StatementParameter.RAW); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("$$inc:junit.test-inc-a$$ $$inc:junit.test-inc-b$$") + .build() + .createQuery("test-inc-a") + .setTemplate(true) + .parseStatement("a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.INTEGER).setDefaultValue("a").build() + .build() + .createQuery("test-inc-b") + .setTemplate(true) + .parseStatement("b=$$b$$ $$inc:junit.test-inc-cc$$") + .createQueryParameter("b", TPQFactory.ParameterValueType.INTEGER).setDefaultValue("a").build() + .build() + .createQuery("test-inc-cc") + .setTemplate(true) + .parseStatement("cc=$$cc$$ $$inc:junit.test-inc-ccc$$") + .createQueryParameter("cc", TPQFactory.ParameterValueType.INTEGER).setDefaultValue("a").build() + .build() + .createQuery("test-inc-ccc") + .setTemplate(true) + .parseStatement("ccc=$$ccc$$") + .createQueryParameter("ccc", TPQFactory.ParameterValueType.INTEGER).setDefaultValue("a").build() + .build() + .build() + .build(); + + Map paraMap = queryManager.getQueryStore().getParameterMetaData("junit.test"); + assertNotNull(paraMap); + assertEquals(4,paraMap.size()); + + TPQueryParameterMetaData paraInfoA = paraMap.get("a"); + TPQueryParameterMetaData paraInfoB = paraMap.get("b"); + TPQueryParameterMetaData paraInfoCC = paraMap.get("cc"); + TPQueryParameterMetaData paraInfoCCC = paraMap.get("ccc"); + assertNotNull(paraInfoA); + assertNotNull(paraInfoB); + assertNotNull(paraInfoCC); + assertNotNull(paraInfoCCC); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerStatementCacheTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerStatementCacheTest.java new file mode 100644 index 0000000..5bf4f41 --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerStatementCacheTest.java @@ -0,0 +1,288 @@ +package net.forwardfire.tpquery.store.manager; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.Lock; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.config.TPQConfig; +import net.forwardfire.tpquery.statement.parameter.TPQStatementParameterListMapper; +import net.forwardfire.tpquery.statement.parameter.TPQStatementParameterValueMapper; +import net.forwardfire.tpquery.store.TPQueryStoreStatement; + +import org.junit.Test; + +public class TPQStoreManagerStatementCacheTest { + + private Lock createFailingLock(boolean lockOke) { + return (Lock)Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Lock.class}, new InvocationHandler() { + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (lockOke && method.getName().equals("lock")) { + return null; + } + throw new IllegalStateException(); + } + }); + } + + @SuppressWarnings("serial") + @Test(expected=IllegalStateException.class) + public void testCacheFailPut() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + Map cc = new HashMap() { + @Override + public TPQueryStoreStatement put(String key,TPQueryStoreStatement value) { + throw new IllegalStateException(); + } + }; + config.setStatementCache(new TPQStoreManagerStatementCache(cc)); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setDefaultValue("a").build() + .build() + .build() + .build(); + queryManager.getQueryExecutorContext().prepareQuery("junit.test", null); + } + + @Test(expected=IllegalStateException.class) + public void testCacheFailPutLock() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + config.setStatementCache(new TPQStoreManagerStatementCache(new HashMap()) { + @Override + protected Lock getWriteLock() { + return createFailingLock(false); + } + }); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setDefaultValue("a").build() + .build() + .build() + .build(); + queryManager.getQueryExecutorContext().prepareQuery("junit.test", null); + } + + @Test(expected=IllegalStateException.class) + public void testCacheFailPutUnlock() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + config.setStatementCache(new TPQStoreManagerStatementCache(new HashMap()) { + @Override + protected Lock getWriteLock() { + return createFailingLock(true); + } + }); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setDefaultValue("a").build() + .build() + .build() + .build(); + queryManager.getQueryExecutorContext().prepareQuery("junit.test", null); + } + + @SuppressWarnings("serial") + @Test(expected=IllegalStateException.class) + public void testCacheFailGet() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + Map cc = new HashMap() { + @Override + public TPQueryStoreStatement get(Object key) { + throw new IllegalStateException(); + } + }; + config.setStatementCache(new TPQStoreManagerStatementCache(cc)); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setDefaultValue("a").build() + .build() + .build() + .build(); + + queryManager.getQueryExecutorContext().prepareQuery("junit.test", null); + } + + @Test(expected=IllegalStateException.class) + public void testCacheFailGetLock() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + config.setStatementCache(new TPQStoreManagerStatementCache(new HashMap()) { + @Override + protected Lock getWriteLock() { + return createFailingLock(false); + } + }); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setDefaultValue("a").build() + .build() + .build() + .build(); + queryManager.getQueryExecutorContext().prepareQuery("junit.test", null); + } + + @Test(expected=IllegalStateException.class) + public void testCacheFailGetUnlock() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + config.setStatementCache(new TPQStoreManagerStatementCache(new HashMap()) { + @Override + protected Lock getWriteLock() { + return createFailingLock(true); + } + }); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setDefaultValue("a").build() + .build() + .build() + .build(); + queryManager.getQueryExecutorContext().prepareQuery("junit.test", null); + } + + + @SuppressWarnings("unchecked") + @Test() + public void testCacheSerializable() throws Exception { + Map cache = new HashMap<>(); + TPQConfig config = TPQFactory.createConfig(); + config.setStatementCache(new TPQStoreManagerStatementCache(cache)); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$ AND b in ($$b$$)") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setDefaultValue("a").build() + .createQueryParameter("b", TPQFactory.ParameterValueType.STRING).setType("LIST").setDefaultValue("1,2,3").build() + .build() + .build() + .build(); + queryManager.getQueryExecutorContext().prepareQuery("junit.test", null); + + File tempFolder = new File("target/junit"); + tempFolder.mkdirs(); + File tempFile = new File(tempFolder,"test-cache.ser"); + try (FileOutputStream fos = new FileOutputStream(tempFile)) { + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(cache); + oos.flush(); + oos.close(); + } + + Map cache2; + try (FileInputStream fis = new FileInputStream(tempFile)) { + ObjectInputStream ois = new ObjectInputStream(fis); + cache2 = (Map) ois.readObject(); + ois.close(); + } + tempFile.delete(); + + assertEquals(cache.size(),cache2.size()); + } + + @Test(expected=Exception.class) + public void testCacheStatementReadObjectNoData() throws Exception { + Map cache = new HashMap<>(); + TPQConfig config = TPQFactory.createConfig(); + config.setStatementCache(new TPQStoreManagerStatementCache(cache)); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setDefaultValue("a").build() + .build() + .build() + .build(); + queryManager.getQueryExecutorContext().prepareQuery("junit.test", null); + TPQueryStoreStatement c = cache.values().iterator().next(); + assertNotNull(c); + Method m = TPQueryStoreStatement.class.getDeclaredMethod("readObjectNoData", new Class[]{}); + m.setAccessible(true); + m.invoke(c, new Object[]{}); + } + + @Test(expected=Exception.class) + public void testCacheValueMapperReadObjectNoData() throws Exception { + Map cache = new HashMap<>(); + TPQConfig config = TPQFactory.createConfig(); + config.setStatementCache(new TPQStoreManagerStatementCache(cache)); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setDefaultValue("a").build() + .build() + .build() + .build(); + queryManager.getQueryExecutorContext().prepareQuery("junit.test", null); + TPQueryStoreStatement c = cache.values().iterator().next(); + assertNotNull(c); + Method m = TPQStatementParameterValueMapper.class.getDeclaredMethod("readObjectNoData", new Class[]{}); + m.setAccessible(true); + m.invoke(c.getValueMapping().get(0), new Object[]{}); + } + + @Test(expected=Exception.class) + public void testCacheListMapperReadObjectNoData() throws Exception { + Map cache = new HashMap<>(); + TPQConfig config = TPQFactory.createConfig(); + config.setStatementCache(new TPQStoreManagerStatementCache(cache)); + TPQManager queryManager = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:mem:test") + .setLanguage("SQL") + .createQuery("test") + .parseStatement("select * from table where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.STRING).setType("LIST").setDefaultValue("1,2,3").build() + .build() + .build() + .build(); + queryManager.getQueryExecutorContext().prepareQuery("junit.test", null); + TPQueryStoreStatement c = cache.values().iterator().next(); + assertNotNull(c); + Method m = TPQStatementParameterListMapper.class.getDeclaredMethod("readObjectNoData", new Class[]{}); + m.setAccessible(true); + m.invoke(c.getValueMapping().get(0), new Object[]{}); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerTest.java new file mode 100644 index 0000000..523835e --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/store/manager/TPQStoreManagerTest.java @@ -0,0 +1,67 @@ +package net.forwardfire.tpquery.store.manager; + +import java.util.HashMap; +import java.util.Map; + +import net.forwardfire.tpquery.TPQManager; +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.config.TPQConfig; +import net.forwardfire.tpquery.store.TPQueryStoreScriptEngineException; + +import org.junit.Test; + +public class TPQStoreManagerTest { + + @Test(expected=TPQueryStoreScriptEngineException.class) + public void testParameterValueScriptError() throws Exception { + TPQConfig config = TPQFactory.createConfig(); + config.addParameterValueScript("throw 'error'"); + TPQManager store = TPQFactory + .createManagerBuilder(config) + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("test") + .parseStatement("select * from foobar where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.SQL_TIME) + .setDefaultValue("js:time()") + .build() + .build() + .build() + .build(); + //store.getQueryExecutorContext().prepareQuery("junit.test", new HashMap()); + } + + @Test(expected=TPQueryStoreScriptEngineException.class) + public void testCompileScriptError() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("test") + .parseStatement("select * from foobar where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.SQL_TIME) + .setDefaultValue("js:+++++++-------------=========----------+++++++++") + .build() + .build() + .build() + .build(); + store.getQueryExecutorContext().prepareQuery("junit.test", new HashMap()); + } + + @Test(expected=Exception.class) + public void testRuntimeScriptError() throws Exception { + TPQManager store = TPQFactory + .createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.SQL) + .createQuery("test") + .parseStatement("select * from foobar where a=$$a$$") + .createQueryParameter("a", TPQFactory.ParameterValueType.SQL_TIME) + .setDefaultValue("js:throw createObject(java.lang.String,'error')") + .build() + .build() + .build() + .build(); + store.getQueryExecutorContext().prepareQuery("junit.test", new HashMap()); + } +} diff --git a/tpquery-store/src/test/java/net/forwardfire/tpquery/store/proxy/TPQueryProxyFactoryTest.java b/tpquery-store/src/test/java/net/forwardfire/tpquery/store/proxy/TPQueryProxyFactoryTest.java new file mode 100644 index 0000000..686e428 --- /dev/null +++ b/tpquery-store/src/test/java/net/forwardfire/tpquery/store/proxy/TPQueryProxyFactoryTest.java @@ -0,0 +1,98 @@ +package net.forwardfire.tpquery.store.proxy; + +import static org.junit.Assert.assertNotNull; + +import java.util.List; + +import net.forwardfire.tpquery.TPQFactory; +import net.forwardfire.tpquery.TPQManager; + +import org.junit.Test; + +public class TPQueryProxyFactoryTest { + + @Test() + public void testQueryProxy() throws Exception { + TPQManager store = TPQFactory.createManagerBuilder() + .createQuerySet("junit", "jar:junit:mem") + .setLanguage(TPQFactory.StatementLanguage.HQL) + .createQuery("testSelect").appendText("from TestEntity").build() + .createQuery("testSelectSingle") + .appendText("from TestEntity te where te.name=") + .appendParameter("name") + .createQueryParameter("name","text").build() + .build() + .createQuery("testSelectMultiple") + .appendText("from TestEntity te where te.name=") + .appendParameter("name") + .appendText(" and length(te.name) > ") + .appendParameter("minLength") + .createQueryParameter("name","text").build() + .createQueryParameter("minLength","int").build() + .build() + .createQuery("testUpdate") + .appendText("update TestEntity te set te.name=") + .appendParameter("name") + .createQueryParameter("name","text").build() + .build() + .createQuerySetTree("TestEntityFooBarDataService") + .createQuery("testFoo").appendText("from TestEntity").build() + .buildTree() + .build() + .build(); + //TPQExecutorJpa exe = new TPQExecutorJpa(store.getQueryExecutorContext()); + + TPQueryProxyFactory proxy = new TPQueryProxyFactory(); + proxy.registrateResultHandler(Object.class, (queryName,parameters) -> null); + proxy.registrateResultHandler(List.class, (queryName,parameters) -> null); + proxy.registrateResultHandler(void.class, (queryName,parameters) -> null); + proxy.registrateResultHandler(int.class, (queryName,parameters) -> null); + proxy.registrateResultHandler(Integer.class, (queryName,parameters) -> null); //exe.executeUpdate(em, queryName, parameters) + + TestEntityDataService dataService = proxy.newProxyInstance(TestEntityDataService.class); + TestEntityFooBarDataService foobarService = proxy.newProxyInstance(TestEntityFooBarDataService.class); + + List d = dataService.testSelect(); + //assertNotNull(d); + + d = dataService.testSelectMultiple(1,"abc1"); + d = dataService.testSelectMultiple(2,"abc2"); + d = dataService.testSelectMultiple(3,"abc3"); + //assertNotNull(d); + + d = foobarService.testFoo(); + //assertNotNull(d); + } + + @TPQueryProxy(prefix="junit.") + public interface TestEntityDataService { + + List testSelect(); + + @TPQueryName("testSelectSingle") + TestEntity testSelectSingle( + @TPQueryParameterName("name") + String name + ); + + List testSelectMultiple( + @TPQueryParameterName("minLength") + int length, + @TPQueryParameterName("name") + String name + ); + + void testUpdate(@TPQueryParameterName("name")String name); + } + + @TPQueryProxy(prefix="junit.%s.") + interface TestEntityFooBarDataService { + + @TPQueryName() + List testFoo(); + } + + class TestEntity { + + } +} diff --git a/tpquery-store/src/test/resources/net/forwardfire/tpquery/test-include-loop.xml b/tpquery-store/src/test/resources/net/forwardfire/tpquery/test-include-loop.xml new file mode 100644 index 0000000..f5a38c9 --- /dev/null +++ b/tpquery-store/src/test/resources/net/forwardfire/tpquery/test-include-loop.xml @@ -0,0 +1,18 @@ + + + + loopInclude:$$inc:test.inc.a$$ + + + + a:$$inc:test.inc.b$$ + + + b:$$inc:test.inc.c$$ + + + c:$$inc:test.inc.a$$ + + + + diff --git a/tpquery-store/src/test/resources/net/forwardfire/tpquery/test-include-multiple.xml b/tpquery-store/src/test/resources/net/forwardfire/tpquery/test-include-multiple.xml new file mode 100644 index 0000000..633c8be --- /dev/null +++ b/tpquery-store/src/test/resources/net/forwardfire/tpquery/test-include-multiple.xml @@ -0,0 +1,23 @@ + + + + + SELECT + ps.jan $$inc:test.inc.inc.valueOffset$$ AS jan, + ps.feb $$inc:test.inc.inc.valueOffset$$ AS feb, + ps.mar $$inc:test.inc.inc.valueOffset$$ AS mar, + ps.mrt $$inc:test.inc.inc.valueOffset$$ AS mrt + FROM + price_stats ps + + + + Duplicate inc to test treeLock naming. + + + +sum(select offset from price_list where key='stats_correction') + + + + + diff --git a/tpquery-store/src/test/resources/net/forwardfire/tpquery/test-query.xml b/tpquery-store/src/test/resources/net/forwardfire/tpquery/test-query.xml new file mode 100644 index 0000000..75242f7 --- /dev/null +++ b/tpquery-store/src/test/resources/net/forwardfire/tpquery/test-query.xml @@ -0,0 +1,56 @@ + + + + + SELECT a.* + + + FROM article a + + + WHERE 1=1 + + + AND ((a.type = $$type_a$$ ) || ($$type_a$$ != -1) || (a.type = $$type_b$$ ) || ($$type_b$$ != -1)) + + + + + AND a.status IN ( $$status$$ ) + + + + ORDER BY $$orderColumn$$ $$orderDirection$$ + + + + + + + $$inc:article.inc.select$$ + $$inc:article.inc.from$$ + $$inc:article.inc.where$$ + $$inc:article.inc.whereType$$ + $$inc:article.inc.whereStatus$$ + $$inc:article.inc.orderBy$$ + + + + + $$inc:article.inc.select$$ + $$inc:article.inc.from$$ + $$inc:article.inc.where$$ + $$inc:article.inc.orderBy$$ + + + + + INSERT INTO article (id,status,name) VALUES ( $$id$$ ,$$status$$ ,$$name$$ ) + + + + + + + + diff --git a/versions.md b/versions.md new file mode 100644 index 0000000..8e8d392 --- /dev/null +++ b/versions.md @@ -0,0 +1,6 @@ + +# TPQuery versions + +## Version x.x.0 +* First public release +* Fourth rewrite of idea.