diff --git a/.github/workflows/unit-tests-push.yml b/.github/workflows/unit-tests-push.yml new file mode 100644 index 00000000..17e4cfb8 --- /dev/null +++ b/.github/workflows/unit-tests-push.yml @@ -0,0 +1,77 @@ +name: Application tests + +on: + push: + branches: + - master + - unit-tests + - develop + pull_request: + types: [opened, synchronize, reopened] + +jobs: + app-tests-analyze: + runs-on: ubuntu-latest + services: + mysql: + image: mysql:latest + env: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: test_database + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + + steps: + - uses: actions/checkout@v2 + + - name: Cache Maven packages + uses: actions/cache@v2 + with: + path: | + ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-m2 + + - name: Set up JDK 17 + uses: actions/setup-java@v1 + with: + java-version: '17' + + - name: Add exec permission to mvnw + run: chmod +x mvnw + + - name: Compile the application + run: ./mvnw -B clean install -DskipTests=true + + - name: Start the application + run: | + ./mvnw spring-boot:run > logs.txt 2>&1 & + echo $! > spring-boot-app.pid + sleep 5 + env: + SPRING_DATASOURCE_URL: jdbc:mysql://localhost:3306/test_database + SPRING_DATASOURCE_USERNAME: root + SPRING_DATASOURCE_PASSWORD: root + SPRING_DATASOURCE_DRIVER_CLASS_NAME: com.mysql.cj.jdbc.Driver + SPRING_PROFILES_ACTIVE: test + - name: Check listening ports + run: ss -tuln + - name: Run tests + run: | + ./mvnw org.jacoco:jacoco-maven-plugin:prepare-agent verify -Dspring.datasource.url=jdbc:mysql://localhost:3306/test_database -Dspring.datasource.username=root -Dspring.datasource.password=root -Dspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + env: + SPRING_PROFILES_ACTIVE: test + headless: true + EXCLUDE_JUNIT: true + - name: Show app logs + if: always() + run: | + cat logs.txt + - name: Shut down the application + run: | + kill $(cat spring-boot-app.pid) + - name: Collect Jacoco report and send to Sonar + run: | + ./mvnw org.jacoco:jacoco-maven-plugin:report sonar:sonar -Dsonar.projectKey=Arquisoft_wiq_es04b -Dsonar.organization=arquisoft -Dsonar.branch.name=${{ github.ref }} -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=${{ secrets.SONAR_TOKEN }} -Dspring.profiles.active=test \ No newline at end of file diff --git a/database/hsqldb/index.html b/database/hsqldb/index.html deleted file mode 100644 index a8fe5467..00000000 --- a/database/hsqldb/index.html +++ /dev/null @@ -1,150 +0,0 @@ - - - - - HSQLDB - - - HyperSQL logo -


-

-

HyperSQL version 2.7.2 Distribution
-

-

HSQLDB (HyperSQL Database) is a relational - database management system written in Java. Now in its 23rd year, - HSQLDB version 2.7.2 is the result of 12 years - improvements since version 2.0. It offers many features and - adheres closely to the latest SQL and JDBC 4.2 standards.

-

This release should be used in preference to earlier 2.x - releases, as it fixes a number of bugs and regressions, as well as - improving functionality and adding new features.

-

The main jars in this package are Java module jars and compatible - with Java 11 and later. The alternative jars are compatible with - Java 8 and later. The jars have been tested with JRE 8, 11 and 17. - A separate jar from the web site has the same functionality as - version 2.7.2 minus the java.time features and can be used with Java 6 and 7. -

-

SUPPORTWARE

-

The development and maintenance of  HyperSQL has been - possible - because of financial contributions by business users. We need - renewed - contributions. Please subscribe to SupportWare at  http://hsqldb.org/web/supportware - . Especially if you include HSQLDB as part of an applications that - you sell, - or use it in production, you are expected to subscribe to - SupportWare at the appropriate level. Subscribers get priority for - support and feature requests.

-

COMMERCIAL SUPPORT

-

Hourly paid support for HyperSQL is available - from http://hyperxtreme.co.uk. - This service provides all the help needed to use or integrate - HSQLDB with your application.

-

SCALABILITY UPGRADES

-

For applications that require more speed with very large data - sets, or need to store more data in a memory database, the - commercial product, HyperXtremeSQL is available - from http://hyperxtreme.co.uk. - This product is fully compatible with HSQLDB SQL queries and JDBC - calls. It also has - extensive SQL OLAP and procedural language features, together with - extra crash-recovery and database management capabilities.

-

PACKAGE CONTENTS

-

This download contains the following files and directories:

-

bin

-

This directory contains some Windows utility wrapper scripts.

-

build

-

This directory contains the ant - build.xml script and Gradle build files. See the Building HyperSQL Jars - appendix of the HyperSQL User Guide for details.

-

classes

-

When the jar is rebuilt, this - directory contains the *.class files generated by the ANT build - tool. - It does not exist in the distribution zip.

-

doc

-

A set of HTML, PDF and text - documents covering different aspects of HSQLDB and some of its - utilities.

-

HyperSQL - User Guide in HTML format.
- HyperSQL User Guide - in PDF format.

-

HyperSQL - Utilities Guide in HTML format.
- HyperSQL - Utilities Guide in PDF - format.

-

The JavaDoc - for public classes, including the JDBC documentation.

-

Chronological list of - minor changes and bug fixes since the release of version 2.0 changelist_2_0.txt -

-

HyperSQL source and binaries are released under the 3-clause BSD - license. The license text hsqldb_lic.txt - is for sources developed entirely by the HSQL Development Group. - The hypersonic_lic.txt - is for the few sources that contain code from the closed - HypersonicSQL project.

-

lib

-

The jar needed for running HyperSQL - and its GUI utilities (hsqldb.jar) has been pre-built in this - directory. The jar for SqlTool (sqltool.jar) is - also in this directory. The jars are - compatible with Java version 8 and above. The extra zip file in - the directory is needed - only for - recompiling hsqldb and is not required for deployment.

-

src

-

All source code is in this directory.

-

testrun

-

Contains test scripts for the - database engine and SqlTool. These scripts are run by separate - test - utilities for the engine and SqlTool

-

doc-src

-

All source code for documentation is in this directory.

-

CHANGES

- -

UPDATES

-

We constantly fix reported issues. Please check the web site - regularly - for latest updated version and latest information. Follow us - on Twitter @hypersql for updates.

-

RESOURCES

-

Support documentation for HyperSQL including the FAQ and links to - resources are available - from http://hsqldb.org/support - in various forms, including user forums. Support is given to open - source developers for using HSQLDB in their products.

-

NOTE

- The highly configurable java source code formatter Jindent is used to format the HSQLDB - source code. -

This Software is developed and published by the HSQL Development - Group

-

Fred Toussi (fredt (at) - users.sourceforge.net)
- Blaine Simpson (blaine dot simpson (at) admc dot com)

-

http://hsqldb.org 

- - diff --git a/database/hsqldb/integration/ant/preprocessor/build.cmd b/database/hsqldb/integration/ant/preprocessor/build.cmd deleted file mode 100644 index 654a7be3..00000000 --- a/database/hsqldb/integration/ant/preprocessor/build.cmd +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -@setlocal -..\..\..\build\setenv.cmd -ant -@endlocal diff --git a/database/hsqldb/integration/ant/preprocessor/build.xml b/database/hsqldb/integration/ant/preprocessor/build.xml deleted file mode 100644 index 7c41ecaf..00000000 --- a/database/hsqldb/integration/ant/preprocessor/build.xml +++ /dev/null @@ -1,215 +0,0 @@ - - - Builds the Ant preprocessor integration jar - - Ant version: ${ant.version} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/database/hsqldb/integration/ant/preprocessor/sample/ATest.exp b/database/hsqldb/integration/ant/preprocessor/sample/ATest.exp deleted file mode 100644 index c3aad2e6..00000000 --- a/database/hsqldb/integration/ant/preprocessor/sample/ATest.exp +++ /dev/null @@ -1,13 +0,0 @@ -class ATest { -// JDBC Version is GTE 4: -String msg4 = "I was included because jdbc_version was GTE 4"; -// JDBC Version is GTE 3 and LT 4: -String msg3 = "I was included because jdbc_version was GTE 3 and LT 4"; -// JDBC Version is GTE 2 and LT 3: -String msg2 = "I was included because jdbc_version was GTE 2 and LT 3"; -String s1 = "v1 was defined"; -String s2 = "v2 was defined"; -String s3 = "v1 was \"happy\""; -String s4 = "v2 was \"sad\""; -String s5 = "v1 was less than or equal to v2"; -} diff --git a/database/hsqldb/integration/ant/preprocessor/sample/ATest.src b/database/hsqldb/integration/ant/preprocessor/sample/ATest.src deleted file mode 100644 index 6a1b0bc0..00000000 --- a/database/hsqldb/integration/ant/preprocessor/sample/ATest.src +++ /dev/null @@ -1,41 +0,0 @@ -class ATest { -//#ifndef jdbc_version -// jdbc_version was not defined: -//#else -//#include Main.inc -//#endinclude -//#endif -//#define jdbc_version 3 -//#include Main.inc -//#endinclude -//#define jdbc_version 2 -//#include Main.inc -//#endinclude -//#define v1 "happy" -//#define v2 "sad" -//#ifdef v1 -String s1 = "v1 was defined"; - //#ifdef v2 -String s2 = "v2 was defined"; - //#if (v1 == "happy") -String s3 = "v1 was \"happy\""; - //#if (v2 == "sad") -String s4 = "v2 was \"sad\""; - //#if (v1 <= v2) -String s5 = "v1 was less than or equal to v2"; - //#else -String s5 = "v1 was greater than v2"; - //#endif (v1 <= v2) - //#else -String s4 = "v2 was not \"sad\""; - //#endif (v2 == "sad") - //#else -String s3 = "v2 was not defined or v1 was not \"happy\""; - //#endif (v1 == "happy") - //#else -String s2 = "v2 was not defined"; - //#endif v1 -//#else -String s1 = "v1 was not defined"; -//#endif v1 -} \ No newline at end of file diff --git a/database/hsqldb/integration/ant/preprocessor/sample/Jdbc2.inc b/database/hsqldb/integration/ant/preprocessor/sample/Jdbc2.inc deleted file mode 100644 index 4157c15f..00000000 --- a/database/hsqldb/integration/ant/preprocessor/sample/Jdbc2.inc +++ /dev/null @@ -1 +0,0 @@ -String msg2 = "I was included because jdbc_version was GTE 2 and LT 3"; \ No newline at end of file diff --git a/database/hsqldb/integration/ant/preprocessor/sample/Jdbc3.inc b/database/hsqldb/integration/ant/preprocessor/sample/Jdbc3.inc deleted file mode 100644 index 35127c9b..00000000 --- a/database/hsqldb/integration/ant/preprocessor/sample/Jdbc3.inc +++ /dev/null @@ -1 +0,0 @@ -String msg3 = "I was included because jdbc_version was GTE 3 and LT 4"; \ No newline at end of file diff --git a/database/hsqldb/integration/ant/preprocessor/sample/Jdbc4.inc b/database/hsqldb/integration/ant/preprocessor/sample/Jdbc4.inc deleted file mode 100644 index ed2651cd..00000000 --- a/database/hsqldb/integration/ant/preprocessor/sample/Jdbc4.inc +++ /dev/null @@ -1 +0,0 @@ -String msg4 = "I was included because jdbc_version was GTE 4"; \ No newline at end of file diff --git a/database/hsqldb/integration/ant/preprocessor/sample/Main.inc b/database/hsqldb/integration/ant/preprocessor/sample/Main.inc deleted file mode 100644 index 1a38d52b..00000000 --- a/database/hsqldb/integration/ant/preprocessor/sample/Main.inc +++ /dev/null @@ -1,20 +0,0 @@ -//#if (jdbc_version >= 4) -// JDBC Version is GTE 4: - //#include Jdbc4.inc - // This is where the JDBC 4 stuff will go... - //#endinclude -//#elif (jdbc_version >= 3) -// JDBC Version is GTE 3 and LT 4: - //#include Jdbc3.inc - // This is where the JDBC 3 stuff will go... - //#endinclude -//#elif (jdbc_version >= 2) -// JDBC Version is GTE 2 and LT 3: - //#include Jdbc2.inc - // This is where the JDBC 2 stuff will go... - //#endinclude -//#elif (jdbc_version >= 1) -// JDBC Version is GTE 1 and LT 2: -//#else -// JDBC Version is LT 1: -//#endif \ No newline at end of file diff --git a/database/hsqldb/integration/ant/preprocessor/src/org/hsqldb/util/preprocessor/ant/AntResolver.java b/database/hsqldb/integration/ant/preprocessor/src/org/hsqldb/util/preprocessor/ant/AntResolver.java deleted file mode 100644 index 1797ca45..00000000 --- a/database/hsqldb/integration/ant/preprocessor/src/org/hsqldb/util/preprocessor/ant/AntResolver.java +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (c) 2001-2007, The HSQL Development Group - * 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. - * - * Neither the name of the HSQL Development Group nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 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 HSQL DEVELOPMENT GROUP, HSQLDB.ORG, - * 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 org.hsqldb.util.preprocessor.ant; - -import java.io.File; -import org.apache.tools.ant.Project; -import org.hsqldb.util.preprocessor.IResolver; - - -/** - * Resolves properties and paths using an ANT Project. - * - * @author Campbell Burnet (campbell-burnet@users dot sourceforge.net) - * @version 2.6.2 - * @since 1.8.1 - */ -public class AntResolver implements IResolver { - - private final Project project; - - public AntResolver(final Project project) { - this.project = project; - } - - @Override - public String resolveProperties(String expression) { - return this.project.replaceProperties(expression); - } - - @Override - public File resolveFile(String path) { - return this.project.resolveFile(path); - } -} diff --git a/database/hsqldb/integration/ant/preprocessor/src/org/hsqldb/util/preprocessor/ant/PreprocessorAntTask.java b/database/hsqldb/integration/ant/preprocessor/src/org/hsqldb/util/preprocessor/ant/PreprocessorAntTask.java deleted file mode 100644 index a47f7ce5..00000000 --- a/database/hsqldb/integration/ant/preprocessor/src/org/hsqldb/util/preprocessor/ant/PreprocessorAntTask.java +++ /dev/null @@ -1,243 +0,0 @@ -/* Copyright (c) 2001-2022, The HSQL Development Group - * 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. - * - * Neither the name of the HSQL Development Group nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 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 HSQL DEVELOPMENT GROUP, HSQLDB.ORG, - * 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 org.hsqldb.util.preprocessor.ant; - -import java.io.File; - -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.taskdefs.MatchingTask; -import org.hsqldb.util.preprocessor.IResolver; -import org.hsqldb.util.preprocessor.Option; -import org.hsqldb.util.preprocessor.Preprocessor; - -/** - *

Provides a facility for invoking the Preprocessor from ANT.

- *

Example ANT target:

{@code 
- *
- *     
- *
- *     
- *     
- *
- * }

Task Attributes

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
NameDescription
srcdir (required)file - directory under which input files are located
targetdir (required)file - directory under which output files are to be written
altext (optional)string - alternate extension to use for output file names.
- * If needed, leading dot should be provided
backup (optional - default: false)boolean - whether to back up pre-existing target files.
- * When true, pre-existing target files are preserved by renaming with - * postfix "~"
encoding (optional)string - the encoding with which to read and write file content.
- * If specified, must be a valid Java encoding identifier, such as "UTF8".
- * When unspecified, the default Java platformn encoding is used.
filter (optional - default: false)boolean - whether to exclude directive lines from output.
indent (optional - default: false)boolean - whether to indent directive lines in output.
symbols (optional)string - CSV list of preprocessor symbols to predefine.
- * When specified, each list element must be of the form:
- * {@code IDENT (ASSIGN? (STRING | NUMBER | IDENT) )?}
- * Note that forward assignments are illegal.
- * See {@link Preprocessor Preprocessor} for details
testonly (optional - default: false)boolean - whether to omit writing output files.
verbose (optional - default: false)boolean - whether to log detailed information.
- * - * @author Campbell Burnet (campbell-burnet@users dot sourceforge.net) - * @version 2.6.2 - * @since 1.8.1 - */ -public class PreprocessorAntTask extends MatchingTask { - - private String ifExpr; - private String unlessExpr; - private File sourceDir; - private File targetDir; - private String defines; - private String altExt; - private String encoding; - private int options = Option.INDENT; - - public void init() { - super.init(); - } - - public void setSrcdir(final File value) { - sourceDir = value; - } - - public void setTargetdir(final File value) { - targetDir = value; - } - - public void setSymbols(final String value) { - defines = value; - } - - public void setVerbose(final boolean verbose) { - options = Option.setVerbose(options, verbose); - } - - public void setBackup(final boolean backup) { - options = Option.setBackup(options, backup); - } - - public void setIndent(final boolean indent) { - options = Option.setIndent(options, indent); - } - - public void setTestonly(final boolean testOnly) { - options = Option.setTestOnly(options, testOnly); - } - - public void setFilter(final boolean filter) { - options = Option.setFilter(options, filter); - } - - public void setAltext(final String ext) { - this.altExt = ext; - } - - public void setEncoding(final String encoding) { - this.encoding = encoding; - } - - public void setIf(final String expr) { - this.ifExpr = expr; - } - - public void setUnless(final String expr) { - this.unlessExpr = expr; - } - - public boolean isActive() { - return (this.ifExpr == null - || getProject().getProperty(this.ifExpr) != null - || this.unlessExpr == null - || getProject().getProperty(this.unlessExpr) == null); - } - - public void execute() throws BuildException { - - if (!isActive()) { - return; - } - - checkSourceDir(); - checkTargetDir(); - - this.sourceDir = getProject().resolveFile("" + this.sourceDir); - - IResolver resolver = new AntResolver(getProject()); - String[] files = getFiles(); - - log("Preprocessing " + files.length + " file(s)"); - - try { - Preprocessor.preprocessBatch(this.sourceDir, this.targetDir, files, - this.altExt, this.encoding, this.options, this.defines, - resolver); - } catch (Exception ex) { - ex.printStackTrace(); - - throw new BuildException("Preprocessing failed: " + ex, - ex); - } - } - - private String[] getFiles() { - return getDirectoryScanner(sourceDir).getIncludedFiles(); - } - - private void checkSourceDir() throws BuildException { - if (this.sourceDir == null) { - throw new BuildException("Source directory is required."); - } - } - - private void checkTargetDir() throws BuildException { - if (targetDir == null) { - throw new BuildException("Target directory is required."); - } - } -} diff --git a/database/hsqldb/integration/extAuthWithSpring/build.xml b/database/hsqldb/integration/extAuthWithSpring/build.xml deleted file mode 100644 index 17c56c5c..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/build.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - You must set Ant property 'authentication.mode' to either - "LDAP" or "JAAS" or "HsqldbSlave" or "JAAS_LDAP". - - Ant property 'hsqldb.jarfile' is required. - To get it using Ivy, SEE COMMENTS THE BUILD FILE. - - - - - - - - - - - - - diff --git a/database/hsqldb/integration/extAuthWithSpring/ivy-projsetup.xml b/database/hsqldb/integration/extAuthWithSpring/ivy-projsetup.xml deleted file mode 100644 index 77d5b5ec..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/ivy-projsetup.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -Add Ivy jar file to Ant CLASSPATH. -Copy-and-paste this for any Bourne shell (inc. Bash): - - export ANT_ARGS; ANT_ARGS='-lib ${basedir}/../../build/ivy-2.2.0.jar -noclasspath' - -OR copy-and-paste this for any CMD-like Windows shell: - - SET ANT_ARGS=-lib "${basedir}/../../build/ivy-2.2.0.jar" -noclasspath - - diff --git a/database/hsqldb/integration/extAuthWithSpring/ivy.xml b/database/hsqldb/integration/extAuthWithSpring/ivy.xml deleted file mode 100644 index 1c8cb6e0..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/ivy.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/database/hsqldb/integration/extAuthWithSpring/ivysettings.xml b/database/hsqldb/integration/extAuthWithSpring/ivysettings.xml deleted file mode 100644 index 0b94e7c4..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/ivysettings.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - diff --git a/database/hsqldb/integration/extAuthWithSpring/jul.properties b/database/hsqldb/integration/extAuthWithSpring/jul.properties deleted file mode 100644 index 279bd895..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/jul.properties +++ /dev/null @@ -1,21 +0,0 @@ -# $Id: jul.properties 3914 2010-11-26 22:11:10Z unsaved $ - -# As this is a Java .properties file, use ISO-8859-1 encoding for any -# extended characters. - -# See http://java.sun.com/javase/6/docs/technotes/guides/logging/overview.html -# for an overview of the JDK logging system, aka the Java Logging API or -# java.util.logging. -# If you want more, and easier, control, particularly over the format of -# output records, use Log4J instead. - -# This is different from the default logging file provided by HyperSQL. -# Here, we purposefully turn up verbosity of the org.hsqldb.sample classes so -# the user can see what is going in the examples. - -handlers=java.util.logging.ConsoleHandler -.level=WARNING - -java.util.logging.ConsoleHandler.level=INFO -java.util.logging.ConsoleHandler.formatter=org.hsqldb.lib.BasicTextJdkLogFormatter -org.hsqldb.sample.level=INFO diff --git a/database/hsqldb/integration/extAuthWithSpring/readme.txt b/database/hsqldb/integration/extAuthWithSpring/readme.txt deleted file mode 100644 index 4d8f02be..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/readme.txt +++ /dev/null @@ -1,37 +0,0 @@ -$Id: readme.txt 3931 2010-12-06 05:10:50Z unsaved $ - -This is the home directory of the extAuthWithSpring sample. - -It uses Spring to declaratively configure external authentication with a -master HyperSQL catalog, or with an LDAP server. - -You will need Ant and a Java JDK installed. To get started, invoke - - ant -Dauthentication.mode=HsqldbSlave - -from this directory to run a JDBC app backed by an application database, with -authentication to the application database through another embedded master -database. Play with the Spring bean files in the resources subdirectory to -switch the application database or the masterdatabase, or anything else. - -To play with a JAAS module, run - - ant -Dauthentication.mode=JAAS - -The file resources/jaas.cfg will be generated the first time that you run -anything with Ant. With mode set to "JAAS", the "demo" application -configuration in jaas.cfg will be used. - -If you have an LDAP server, edit "resources/ldapbeans.xml" to set settings -according to your LDAP server then run ant with the authentication.mode set to -"LDAP". -To help determine and test the settings that will work with your LDAP server, I -recommend that you use the program org.hsqldb.auth.LdapAuthBean. See the -HyperSQL API Spec for org.hsqldb.auth.LdapAuthBean and the sample properties -file for it at "sample/ldap-exerciser.properties" in your HyperSQL distribution. - -As an alternative to LDAP mode, you can use JAAS_LDAP mode. That works very -similarly, but uses Sun's JAAS LDAP module and suffers from its limitations. -It should be easy to figure out how to use by looking over the "sunLdap" -application settings in jaas.cfg, and the Spring bean definitions in -resources/jaasldapbeans.xml. diff --git a/database/hsqldb/integration/extAuthWithSpring/resources/beandefs.xml b/database/hsqldb/integration/extAuthWithSpring/resources/beandefs.xml deleted file mode 100644 index 72dc8ac2..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/resources/beandefs.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/database/hsqldb/integration/extAuthWithSpring/resources/jaasbeans.xml b/database/hsqldb/integration/extAuthWithSpring/resources/jaasbeans.xml deleted file mode 100644 index 7dfc310a..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/resources/jaasbeans.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/database/hsqldb/integration/extAuthWithSpring/resources/jaasldapbeans.xml b/database/hsqldb/integration/extAuthWithSpring/resources/jaasldapbeans.xml deleted file mode 100644 index ec865386..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/resources/jaasldapbeans.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/database/hsqldb/integration/extAuthWithSpring/resources/ldapbeans.xml b/database/hsqldb/integration/extAuthWithSpring/resources/ldapbeans.xml deleted file mode 100644 index dcd9278f..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/resources/ldapbeans.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/database/hsqldb/integration/extAuthWithSpring/resources/slavebeans.xml b/database/hsqldb/integration/extAuthWithSpring/resources/slavebeans.xml deleted file mode 100644 index d41ea009..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/resources/slavebeans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/database/hsqldb/integration/extAuthWithSpring/src/org/hsqldb/sample/JdbcAppClass.java b/database/hsqldb/integration/extAuthWithSpring/src/org/hsqldb/sample/JdbcAppClass.java deleted file mode 100644 index 252f1870..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/src/org/hsqldb/sample/JdbcAppClass.java +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyright (c) 2001-2010, The HSQL Development Group - * 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. - * - * Neither the name of the HSQL Development Group nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 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 HSQL DEVELOPMENT GROUP, HSQLDB.ORG, - * 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 org.hsqldb.sample; - -import java.sql.SQLException; -import java.sql.ResultSet; -import java.sql.Connection; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import javax.sql.DataSource; - -/** - * An application class that performs some simple JDBC work. - * - * This class is purposefully not Spring-aware. - */ -public class JdbcAppClass { - private static Log log = LogFactory.getLog(JdbcAppClass.class); - - private boolean initialized; - private DataSource ds; - - public void init() { - if (ds == null) throw new IllegalStateException( - "Required property 'dataSource' not set"); - initialized = true; - } - - public void setDataSource(DataSource ds) { - this.ds = ds; - } - - public void doJdbcWork() throws SQLException { - if (!initialized) - throw new IllegalStateException(JdbcAppClass.class.getName() - + " instance not initialized"); - Connection c = null; - ResultSet rs = null; - try { - c = ds.getConnection(); - rs = c.createStatement().executeQuery("SELECT * FROM t1"); - if (!rs.next()) { - log.error("App class failed to retrieve data from catalog"); - return; - } - if (rs.getInt(1) != 456) { - log.error("App class retrieved wrong value: " + rs.getInt(1)); - return; - } - if (rs.next()) { - log.error("App class failed too much data from catalog"); - return; - } - } finally { - if (c != null) try { - c.rollback(); - } catch (SQLException se) { - // Intentionally empty. - // We have done nothing that we want to commit, but want to - // aggressively free transactional resources. - } - if (rs != null) try { - rs.close(); - } catch (SQLException se) { - log.error("Failed to close emulation database setup Connection", - se); - } finally { - rs = null; // Encourage GC - } - if (c != null) try { - c.close(); - } catch (SQLException se) { - log.error("Failed to close emulation database setup Connection", - se); - } finally { - c = null; // Encourage GC - } - } - log.info("Application Success"); - } -} diff --git a/database/hsqldb/integration/extAuthWithSpring/src/org/hsqldb/sample/SpringExtAuth.java b/database/hsqldb/integration/extAuthWithSpring/src/org/hsqldb/sample/SpringExtAuth.java deleted file mode 100644 index 44c40413..00000000 --- a/database/hsqldb/integration/extAuthWithSpring/src/org/hsqldb/sample/SpringExtAuth.java +++ /dev/null @@ -1,176 +0,0 @@ -/* Copyright (c) 2001-2010, The HSQL Development Group - * 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. - * - * Neither the name of the HSQL Development Group nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 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 HSQL DEVELOPMENT GROUP, HSQLDB.ORG, - * 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 org.hsqldb.sample; - -import java.sql.Connection; -import java.sql.Statement; -import java.sql.DriverManager; -import java.sql.SQLException; -import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.context.ApplicationContext; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * As you can tell by the class name, this class is purposefully Spring-aware, - * as it initiates the Spring Spring context load. - * In a web application, a lifecycle lister or other - * mechanism would eliminate the need for any custom Java code to load the - * context (like what we have here). - */ -public class SpringExtAuth { - private static Log log = LogFactory.getLog(SpringExtAuth.class); - - private static final String SYNTAX_MSG = "SYNTAX: " - + SpringExtAuth.class.getName() - + " {LDAP|HsqldbSlave|JAAS|JAAS_LDAP}"; - - /** - * @throws SQLException If Setup of emulation database failed, or if the - * application JDBC work fails. - */ - static public void main(String[] sa) throws SQLException { - if (sa.length != 1) throw new IllegalArgumentException(SYNTAX_MSG); - String authSpringFile = null; - if (sa[0].equals("LDAP")) { - authSpringFile = "ldapbeans.xml"; - } else if (sa[0].equals("JAAS")) { - authSpringFile = "jaasbeans.xml"; - } else if (sa[0].equals("HsqldbSlave")) { - authSpringFile = "slavebeans.xml"; - } else if (sa[0].equals("JAAS_LDAP")) { - authSpringFile = "jaasldapbeans.xml"; - } - if (authSpringFile == null) - throw new IllegalArgumentException(SYNTAX_MSG); - - SpringExtAuth.prepMemoryDatabases(!sa[0].equals("HsqldbSlave")); - ApplicationContext ctx = - new ClassPathXmlApplicationContext("beandefs.xml", authSpringFile); - ListableBeanFactory bf = (ListableBeanFactory) ctx; - JdbcAppClass appBean = bf.getBean("appBean", JdbcAppClass.class); - appBean.doJdbcWork(); - } - - /** - * This method prepares a memory-only catalog. - * After this method runs, a new Connection using the same JDBC URL will - * behave just like connecting to a populated, persistent catalog. - * - * Purposefully not using declarative settings here because this is purely - * emulation setup. - * A real application won't have any method corresponding to this method. - * - * @throws SQLException if setup failed - */ - private static void prepMemoryDatabases(boolean doLdap) - throws SQLException { - Connection c = null; - Statement st = null; - try { - c = DriverManager.getConnection( - "jdbc:hsqldb:mem:localDb", "SA", ""); - // JDBC URL here must match that configured within the bean - // 'appBean' in "beandefs.xml" file - c.setAutoCommit(false); - st = c.createStatement(); - st.executeUpdate("SET DATABASE UNIQUE NAME \"AUTHSAMPLEDBNAME\""); - st.executeUpdate( - "SET DATABASE AUTHENTICATION FUNCTION EXTERNAL NAME " - + "'CLASSPATH:" - + "org.hsqldb.auth.AuthBeanMultiplexer.authenticate'"); - // DB Name here must match that configured in either - // "ldapbeans.xml" or "slavebean.xml", depending on whether you are - // running in LDAP or HsqldbSlave mode, correspondingly. - st.executeUpdate("SET PASSWORD 'SECRET5222173'"); - st.executeUpdate("CREATE TABLE t1(i INTEGER)"); - st.executeUpdate("GRANT SELECT ON t1 TO public"); - st.executeUpdate("INSERT INTO t1 VALUES(456)"); - // Table name and value must match what is expected by method - // JdbcAppClass.doJdbcWork. - c.commit(); - } finally { - if (st != null) try { - st.close(); - } catch (SQLException se) { - log.error("Failed to close emulation database setup Connection", - se); - } finally { - st = null; // Encourage GC - } - if (c != null) try { - c.close(); - } catch (SQLException se) { - log.error("Failed to close emulation database setup Connection", - se); - } finally { - c = null; // Encourage GC - } - } - if (doLdap) return; - - // Create an authentication master database - try { - c = DriverManager.getConnection( - "jdbc:hsqldb:mem:masterDb", "SA", ""); - // JDBC URL here must match that configured for bean - // 'slaveSetup' in "slavebeans.xml" file - c.setAutoCommit(false); - st = c.createStatement(); - st.executeUpdate("SET PASSWORD 'SECRET9123113'"); - // This password will never be used again. - // Changing it from the default just for good security practice. - st.executeUpdate("CREATE USER \"straight\" PASSWORD 'pwd'"); - // User name and password here must match those configured in file - // "beandefs.xml". - c.commit(); - } finally { - if (st != null) try { - st.close(); - } catch (SQLException se) { - log.error("Failed to close emulation database setup Connection", - se); - } finally { - st = null; // Encourage GC - } - if (c != null) try { - c.close(); - } catch (SQLException se) { - log.error("Failed to close emulation database setup Connection", - se); - } finally { - c = null; // Encourage GC - } - } - } -} diff --git a/database/hsqldb/integration/jackrabbit/readme.txt b/database/hsqldb/integration/jackrabbit/readme.txt deleted file mode 100644 index 59f111d9..00000000 --- a/database/hsqldb/integration/jackrabbit/readme.txt +++ /dev/null @@ -1,31 +0,0 @@ -This directory contains access files for Apache Jackrabbit (http://jackrabbit.apache.org/) - -The ddl file for jackrabbit version 2.x is located at: - -resources/org/apache/jackrabbit/core/persistence/bundle/hsqldb.ddl - -This ddl file can be used with the default BundleDbPersistenceManager - -Copy the ddl file to the same directory in your Jackrabbit setup, alongside the existing -ddl files. For example jackrabbit-standalone-2.2.4/org/apache/jackrabbit/core/persistence/bundle - -A sample configuration is given below. The DDL table definitions use BLOBs, which -are stored on disk. - -If you are storing no more than several thousand objects, the non-blob fields can be stored in -memory for quicker access with hsqldb.default_table_type=memory. See the hsqldb documentation -at http://hsqldb.org/doc/2.0/ for different connection URL and other properties that can be used. - - - - - - - - - -A ddl file for older versions of Jackrabbit is also included in the ...core/persistence/db directory. - -All files are modified copies of existing Jackrabbit sources. - - diff --git a/database/hsqldb/integration/jackrabbit/resources/org/apache/jackrabbit/core/journal/hsqldb.ddl b/database/hsqldb/integration/jackrabbit/resources/org/apache/jackrabbit/core/journal/hsqldb.ddl deleted file mode 100644 index a9a73d35..00000000 --- a/database/hsqldb/integration/jackrabbit/resources/org/apache/jackrabbit/core/journal/hsqldb.ddl +++ /dev/null @@ -1,22 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -create table ${schemaObjectPrefix}JOURNAL (REVISION_ID BIGINT NOT NULL, JOURNAL_ID varchar(255), PRODUCER_ID varchar(255), REVISION_DATA blob) -create unique index ${schemaObjectPrefix}JOURNAL_IDX on ${schemaObjectPrefix}JOURNAL (REVISION_ID) -create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID BIGINT NOT NULL) -create unique index ${schemaObjectPrefix}GLOBAL_REVISION_IDX on ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID) -create table ${schemaObjectPrefix}LOCAL_REVISIONS (JOURNAL_ID varchar(255) NOT NULL, REVISION_ID BIGINT NOT NULL) - -# Inserting the one and only revision counter record now helps avoiding race conditions -insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0) diff --git a/database/hsqldb/integration/jackrabbit/resources/org/apache/jackrabbit/core/persistence/bundle/hsqldb.ddl b/database/hsqldb/integration/jackrabbit/resources/org/apache/jackrabbit/core/persistence/bundle/hsqldb.ddl deleted file mode 100644 index 88cb7465..00000000 --- a/database/hsqldb/integration/jackrabbit/resources/org/apache/jackrabbit/core/persistence/bundle/hsqldb.ddl +++ /dev/null @@ -1,21 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Bundle persistence DDL script for the HSQLDB database engine (http://www.hsqldb.org) -# -create table ${schemaObjectPrefix}BUNDLE (NODE_ID binary(16) primary key, BUNDLE_DATA blob(2G) not null)) -create table ${schemaObjectPrefix}REFS (NODE_ID binary(16) PRIMARY KEY primary key, REFS_DATA blob(2G) not null)) -create table ${schemaObjectPrefix}BINVAL (BINVAL_ID char(64) PRIMARY KEY, BINVAL_DATA blob(2G) not null) -create table ${schemaObjectPrefix}NAMES (ID INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, NAME varchar(255) not null) diff --git a/database/hsqldb/integration/jackrabbit/resources/org/apache/jackrabbit/core/persistence/db/hsqldb.ddl b/database/hsqldb/integration/jackrabbit/resources/org/apache/jackrabbit/core/persistence/db/hsqldb.ddl deleted file mode 100644 index 7258260c..00000000 --- a/database/hsqldb/integration/jackrabbit/resources/org/apache/jackrabbit/core/persistence/db/hsqldb.ddl +++ /dev/null @@ -1,21 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# DDL script for the HSQLDB database engine (http://www.hsqldb.org) -# -create table ${schemaObjectPrefix}NODE (NODE_ID char(36) primary key, NODE_DATA blob not null) -create table ${schemaObjectPrefix}PROP (PROP_ID varchar(1024) primary key, PROP_DATA blob not null) -create table ${schemaObjectPrefix}REFS (NODE_ID char(36) primary key, REFS_DATA blob not null) -create table ${schemaObjectPrefix}BINVAL (BINVAL_ID varchar(1024) primary key, BINVAL_DATA blob not null) diff --git a/database/hsqldb/integration/readme.txt b/database/hsqldb/integration/readme.txt deleted file mode 100644 index 3dddb51a..00000000 --- a/database/hsqldb/integration/readme.txt +++ /dev/null @@ -1,7 +0,0 @@ -$Id: readme.txt 3900 2010-11-17 03:59:50Z unsaved $ - -Each subdirectory of this directory is a home directory to a sample integration -application. - -See the "readme.txt" file in each subdirectory to see the purpose of that -particular sample. diff --git a/database/hsqldb/readme.txt b/database/hsqldb/readme.txt deleted file mode 100644 index 1e481f28..00000000 --- a/database/hsqldb/readme.txt +++ /dev/null @@ -1,10 +0,0 @@ -Readme File - -This package contains HyperSQL version 2.7.2 - -HyperSQL Database is a relational database management system and a set of tools -written in Java. -HyperSQL is also known as HSQLDB. - -The file "index.html" explains the contents of this distribution and has -links to documentation and support resources. diff --git a/database/hsqldb/sample/StartupParameters.plist b/database/hsqldb/sample/StartupParameters.plist deleted file mode 100644 index c82bb640..00000000 --- a/database/hsqldb/sample/StartupParameters.plist +++ /dev/null @@ -1,21 +0,0 @@ -/* - $Id: StartupParameters.plist 59 2007-04-17 01:08:09Z unsaved $ - Startup Item parameter file that works on at least one Mac OS X system. - - I don't know which of the "Uses" services are available on all Mac's. - I just know that my system has them, and this list causes HSQLDB - to start late enough without resorting to "Latest" (which could cause - problems for people who also start up apps that use HSQLDB). -*/ -{ - Description = "HSQLDB Database Server"; - Provides = ("Hsqldb"); - Requires = ("Resolver"); - Uses = ("Disks", "Network", "Core Services", "TIM", "NetInfo", "Resolver"); - Messages = - { - start = "Starting Hsqldb"; - stop = "Stopping Hsqldb"; - restart = "Restarting Hsqldb"; - }; -} diff --git a/database/hsqldb/sample/acl.txt b/database/hsqldb/sample/acl.txt deleted file mode 100644 index e7d5c3f4..00000000 --- a/database/hsqldb/sample/acl.txt +++ /dev/null @@ -1,31 +0,0 @@ -# $Id: acl.txt 536 2008-12-05 14:55:10Z unsaved $ - -# Sample HyperSQL Network Listener ACL file. -# Specify "allow" and "deny" rules -# For address specifications, individual addresses, host names, and -# network addresses with /bit suffix are allowed, but read the caveat about -# host names below, under the sample "localhost" rule. - -# Blank lines ignored. - # Lines with # as the first non-whitespace character are ignored. - - -allow 2001:db8::/32 -# Allow this 32-bit ipv4 subnet - -allow localhost -# You should use numerical addresses in ACL files, unless you are certain that -# the name will always be known to your network address resolution system -# (assume that you will lose Internet connectivity at some time). -# With a default name resolution setup on UNIX, you are safe to use names -# defined in your /etc/hosts file. - -deny 192.168.101.253 -# Deny a single IP address. -# In our example, 192.168.101.0/24 is our local, organizational network. -# 192.168.101.253 is the IP address of our Intern's PC. -# The Intern does not have permission to access our databases directly. - -allow 192.168.101.0/24 - -# Any ipv4 or ipv6 candidate address not matched above will be denied diff --git a/database/hsqldb/sample/csv-sample.sql b/database/hsqldb/sample/csv-sample.sql deleted file mode 100644 index 90813984..00000000 --- a/database/hsqldb/sample/csv-sample.sql +++ /dev/null @@ -1,65 +0,0 @@ -/* - * $Id: csv-sample.sql 4810 2011-11-20 21:18:10Z unsaved $ - * - * Create a table, CVSV-export the data, import it back. - */ - -* *DSV_COL_DELIM = , -* *DSV_COL_SPLITTER = , --- Following causes a reject report to be written if there are any bad records --- during the import. To test it, enable the "FORCE AN ERROR" block below. -* *DSV_REJECT_REPORT = import.html - --- 1. SETTINGS --- For applications like MS Excel, which can't import or export nulls, we have --- to dummy down our database empty strings to export and import as if they --- were nulls. -* *NULL_REP_TOKEN = - --- Enable following line to quote every cell value --- * *ALL_QUOTED = true - - --- 2. SET UP TEST DATA -CREATE TABLE t (i INT, v VARCHAR(25), d DATE); -INSERT INTO t(i, v, d) VALUES (1, 'one two three', null); -INSERT INTO t(i, v, d) VALUES (2, null, '2007-06-24'); -INSERT INTO t(i, v, d) VALUES (3, 'one,two,,three', '2007-06-24'); -INSERT INTO t(i, v, d) VALUES (4, '"one"two""three', '2007-06-24'); -INSERT INTO t(i, v, d) VALUES (5, '"one,two"three,', '2007-06-24'); -INSERT INTO t(i, v, d) VALUES (6, '', '2007-06-24'); -commit; - --- 3. CSV EXPORT -/* Export */ -\xq t -/* FORCE AN ERROR. Enable the following 3 lines to force a bad CSV record. -\o t.csv -\p barf -\o -*/ - --- 4. BACK UP AND ZERO SOURCE TABLE -CREATE TABLE orig AS (SELECT * FROM t) WITH DATA; -DELETE FROM t; -commit; - --- 5. CSV IMPORT -\mq t.csv -commit; - --- 6. MANUALLY EXAMINE DIFFERENCES BETWEEN SOURCE AND IMPORTED DATA. --- See /testrun/sqltool/csv-roundtrip.sql to see a way to make --- this same comparison programmatically. -* - *NULL_REP_TOKEN -\p -\p ORIGINAL: -SELECT * FROM orig; -\p -\p IMPORTED: -SELECT * FROM t; -\p -\p The empty string in the source table will have been translated to null in -\p the imported data. -\p You can see that the generated CSV file represents both nulls and -\p empty strings as nothing, hence the convergence. diff --git a/database/hsqldb/sample/dsv-sample.sql b/database/hsqldb/sample/dsv-sample.sql deleted file mode 100644 index f9d188e5..00000000 --- a/database/hsqldb/sample/dsv-sample.sql +++ /dev/null @@ -1,37 +0,0 @@ -/* - * $Id: dsv-sample.sql 610 2008-12-22 15:54:18Z unsaved $ - * - * Imports delimiter-separated-values, and generates an output - * reject .dsv file, and a reject report. - * - * To execute, set up a SqlTool database urlid (see User Guide if you don't - * know how to do that); then (from this directory) execute this script like - * - * java ../lib/hsqldb.jar mem dsv-sample.sql - * - * (replace "mem" with your urlid). - */ - -CREATE TABLE sampletable(i INT, d DATE NOT NULL, b BOOLEAN); - -/* If you dont' set *DSV_TARGET_TABLE, it defaults to the base name of the - .dsv file. */ -* *DSV_TARGET_TABLE = sampletable - -\p WARNING: Some records will be skipped, and some others will be rejected. -\p This is on purpose, so you can work with a reject report. -\p - -/* By default, no reject files are written, and the import will abort upon - * the first error encountered. If you set either of these settings, the - * import will continue to completion if at all possible. */ -* *DSV_REJECT_FILE = ${java.io.tmpdir}/sample-reject.dsv -* *DSV_REJECT_REPORT = ${java.io.tmpdir}/sample-reject.html -\m sample.dsv - -/* Enable this line if you want to display all successfully imported data: -SELECT * FROM sampletable; -*/ - -\p -\p See import reject report at '*{*DSV_REJECT_REPORT}'. diff --git a/database/hsqldb/sample/hsqldb.conf b/database/hsqldb/sample/hsqldb.conf deleted file mode 100644 index 9775c745..00000000 --- a/database/hsqldb/sample/hsqldb.conf +++ /dev/null @@ -1,173 +0,0 @@ -# $Id: hsqldb.conf 6310 2021-02-28 15:25:00Z unsaved $ - -# Sample configuration file for HyperSQL Server Listener. -# See the "HyperSQL on UNIX" chapter of the HyperSQL User Guide. - -# N.b.!!!! You must place this in the right location for your type of UNIX. -# See the init script "hsqldb" to see where this must be placed and -# what it should be renamed to. - -# This file is "sourced" by a Bourne shell, so use Bourne shell syntax. - -# This file WILL NOT WORK until you set (at least) the non-commented -# variables to the appropriate values for your system. -# Life will be easier if you avoid all filepaths with spaces or any other -# funny characters. Don't ask for support if you ignore this advice. - -# The URLIDS setting below is new and REQUIRED. This setting replaces the -# server.urlid.X settings which used to be needed in your Server's -# properties file. - -# -- Blaine (blaine dot simpson at admc dot com) - -JAVA_EXECUTABLE=/usr/bin/java - -# Unless you copied the jar files from another system, this typically -# resides at $HSQLDB_HOME/lib/sqltool.jar, where $HSQLDB_HOME is your HSQLDB -# software base directory. -# The file name may actually have a version label in it, like -# sqltool-1.2.3.jar (in which case, you must specify the full name here). -# A 'hsqldb.jar' file (with or without version label) must reside in the same -# directory as the specified sqltool.jar file. -SQLTOOL_JAR_PATH=/opt/hsqldb-2.0.0/hsqldb/lib/sqltool.jar -# For the sample value above, there must also exist a file -# /opt/hsqldb-2.0.0/hsqldb/lib/hsqldb*.jar. - -# Where the file "server.properties" or "webserver.properties" resides. -SERVER_HOME=/opt/hsqldb-2.0.0/hsqldb/data - -# What UNIX user the server will run as. -# (The shutdown client is always run as root or the invoker of the init script). -# Runs as root by default, but you should take the time to set database file -# ownerships to another user and set that user name here. -HSQLDB_OWNER=hsqldb - -# The HSQLDB jar file specified in HSQLDB_JAR_PATH above will automatically -# be in the class path. This arg specifies additional classpath elements. -# To embed your own application, add your jar file(s) or class base -# directories here, and add your main class to the INVOC_ADDL_ARGS setting -# below. Another common use-case for adding to your class path is to make -# classes available to the DB engines for SQL/JRT functions and procedures. -#SERVER_ADDL_CLASSPATH=/usr/local/dist/currencybank.jar - -# For startup or shutdown failures, you can save a lot of debugging time by -# temporarily adjusting down MAX_START_SECS and MAX_TERMINATE_SECS to a -# little over what it should take for successful startup and shutdown on -# your system. - -# We require all Server/WebServer instances to be accessible within -# $MAX_START_SECS from when the Server/WebServer is started. -# Defaults to 60. -# Raise this is you are running lots of DB instances or have a slow server. -#MAX_START_SECS=200 - -# Max time to allow for JVM to die after all HSQLDB instances stopped. -# Defaults to 60. Set high because the script will always continue as soon as -# the process has stopped. The importance of this setting is, how long until -# a non-stopping-JVM-problem will be detected. -#MAX_TERMINATE_SECS=0 - -# NEW AND IMPORTANT!!! -# As noted at the top of this file, this setting replaces the old property -# settings server.urlid.X. -# Simply list the URLIDs for all DB instances which your *Server starts. -# Usually, these will exactly mirror the server.database.X settings in your -# server.properties or webserver.properties file. -# Each urlid listed here must be defined to a NETWORK url with Admin privileges -# in the AUTH_FILE specified below. (Network type because we use this for -# inter-process communication) -# Separate multiple values with white space. NO OTHER SPECIAL CHARACTERS! -# Make sure to quote the entire value if it contains white space separator(s). -URLIDS='localhostdb1' - -# These are urlids # ** IN ADDITION TO URLIDS **, for instances which the init -# script should stop but not start. -# Most users will not need this setting. If you need it, you'll know it. -# Defaults to none (i.e., only URLIDS will be stopped). -#SHUTDOWN_URLIDS='ondemand' - -# SqlTool authentication file used only for shutdown. -# The default value will be sqltool.rc in root's home directory, since it is -# root who runs the init script. -# (See the SqlTool chapter of the HyperSQL Utilities Guide if you don't -# understand this). -#AUTH_FILE=/home/blaine/sqltool.rc - -# Typical users will leave this unset and it will default to -# org.hsqldb.server.Server. If you need to run the HSQLDB WebServer class -# instead, due to a firewall or routing impediment, set this to -# org.hsqldb.server.WebServer, see the docs about running WebServr, and -# set up a "webserver.properties" file instead of a "server.properties". -# The JVM that is started can invoke many classes (see the following item -# about that), but this is the server that is used (1) to check status, -# (2) to shut down the JVM. -#TARGET_CLASS=org.hsqldb.server.WebServer - -# This is where you may specify both command-line parameters to TARGET_CLASS, -# plus any number of additional progams to run (along with their command-line -# parameters). The MainInvoker program is used to embed these multiple -# static main invocations into a single JVM, so see the API spec for -# org.hsqldb.util.MainInvoker if you want to learn more. -# N.b. You should only use this setting to set HSQLDB Server or WebServer -# parameters if you run multiple instances of this class, since you can use the -# server/webserver.properties file for a single instance. -# Every additional class (in addition to the TARGET_CLASS) -# must be preceded with an empty string, so that MainInvoker will know -# you are giving a class name. MainInvoker will invoke the normal -# static main(String[]) method of each such class. -# By default, MainInvoker will just run TARGET_CLASS with no args. -# Example that runs just the TARGET_CLASS with the specified arguments: -#INVOC_ADDL_ARGS='-silent false' #but use server.properties property instead! -# Example that runs the TARGET_CLASS plus a WebServer: -#INVOC_ADDL_ARGS='"" org.hsqldb.server.WebServer' -# Note the empty string preceding the class name. -# Example that starts TARGET_CLASS with an argument + a WebServer + -# your own application with its args (i.e., the HSQLDB Servers are -# "embedded" in your application). (Set SERVER_ADDL_CLASSPATH too).: -#INVOC_ADDL_ARGS='-silent false "" org.hsqldb.server.WebServer "" com.acme.Stone --env prod localhost' -# but use server.properties for -silent option instead! -# Example to run a non-TLS server in same JVM with a TLS server. In this -# case, TARGET_CLASS is Server which will run both in TLS mode by virtue of -# setting the tls, keyStore, and keyStorePassword settings in -# server*.properties, as described below; plus an "additional" Server with -# overridden 'tls' and 'port' settings: -#INVOC_ADDL_ARGS="'' org.hsqldb.server.Server --port 9002 --tls false" -# This is an important use case. If you run more than one Server instance, -# you can specify different parameters for each here, even though only one -# server.properties file is supported. -# Note that you use nested quotes to group arguments and to specify the -# empty-string delimiter. - -# The TLS_* settings have been obsoleted. -# To get your server running with TLS, set -# system.javax.net.ssl.keyStore=/path/to/your/private.keystore -# system.javax.net.ssl.keyStorePassword=secretPassword -# server.ssl=true -# IN server.properties or webserver.properties, and -# MAKE THE FILE OWNER-READ-ONLY! -# See the TLS Encryption section of the HyperSQL User Guide, paying attention -# to the security warning(s). -# If you are running with a private server cert, then you will also need to -# set "truststore" in the your SqlTool config file (location is set by the -# AUTH_FILE variable in this file, or it must be at the default location for -# HSQLDB_OWNER). - -# Any JVM args for the invocation of the JDBC client used to verify DB -# instances and to shut them down (SqlToolSprayer). -# Server-side System Properties should normally be set with system.* -# settings in the server/webserver.properties file. -# This example specifies the location of a private trust store for TLS -# encryption. -# For multiple args, put quotes around entire value. -# If you are starting just a TLS_encrypted Listener, you need to uncomment -# this so the init scripts uses TLS to connect. -# If using a private keystore, you also need to set "truststore" settings in -# the sqltool.rc file. -#CLIENT_JVMARGS=-Djavax.net.debug=ssl -# This sample value displays useful debugging information about TLS/SSL. - -# Any JVM args for the server. -# For multiple args, put quotes around entire value. -#SERVER_JVMARGS=-Xmx512m -# You can set the "javax.net.debug" property on the server side here, in the -# same exact way as shown for the client side above. diff --git a/database/hsqldb/sample/hsqldb.init b/database/hsqldb/sample/hsqldb.init deleted file mode 100644 index 2137094d..00000000 --- a/database/hsqldb/sample/hsqldb.init +++ /dev/null @@ -1,501 +0,0 @@ -#!/bin/sh -# For boot-up and system shutdown, most UNIXes explicitly run a shell -# interpreter. In that case, the interpreter line above is ignored. -# There are a few UNIXes (notably Darwin) that require the interpreter line. - -# Copyright (c) 2001-2008, The HSQL Development Group -# 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. -# -# Neither the name of the HSQL Development Group nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# 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 HSQL DEVELOPMENT GROUP, HSQLDB.ORG, -# 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. - - -# $Id: hsqldb.init 6310 2021-02-28 15:25:00Z unsaved $ - -# UNIX init script for HSQLDB. - -# IMPORTANT! Users running multiple HSQLDB ***Server processes*** must use a -# unique "SERVICE" name for each Server process. Most users will run just one -# server instance, possibly serving lots of database instances. Multi-server -# runners must change the value on the following line, and, if your system -# uses chkconfig or insserv, you must change the value of "hsqldb" to the -# same thing (as SERVICE) in the chkconfig and/or insserv blocks a few -# lines down from here (incl. in the pidfile and config file paths). (Sorry -# to say, but you need to repeat this procedure after every HSQLDB upgrade). -SERVICE=hsqldb -# This is the one setting which users will commonly change in this file. -# It's impossible to determine this script name (in a portable way) at boot-up -# time, since ${0} is entirely different for init scripts, depending on UNIX -# version. - -# See the "HyperSQL on UNIX" chapter of the HyperSQL User Guide for how to -# use this file. -# This block only used by chkconfig systems (incl. SuSE Linux). -# chkconfig: 345 87 13 -# description: HyperSQL Database, A High Performance Java Database Server -# pidfile: /run/hsqldb.pid -# config: /etc/sysconfig/hsqldb - -# This block only used by insserv systems (incl. SuSE Linux). -### BEGIN INIT INFO -# Provides: hsqldb -# Required-Start: $syslog $remote_fs $network $named -# Required-Stop: -# Default-Start: 3 5 -# Default-Stop: 0 1 2 6 -# Short-Description: HyperSQL Database Server -# Description: HyperSQL Database, A High Performance Java Database Server -### END INIT INFO - -# UNIX System-V and Linux users should copy this script to the common -# init script directory (/etc/init.d/ on most systems) with name "hsqldb", -# or whatever you have SERVICE set to (no ".init" suffix!). - -# N.b. Being a system script, this script does not use inherited variables. -# If you want to adjust a setting, edit the config file. - -# Strategy of this init script is to avoid shell-specific functionality, -# and use only lowest-common-denominator Bourne capabilities. -# We don't include OS-specific functions, and we don't use shell- -# implementation-specific functionality like "echo ...\c" or "echo -n...". -# Since some Bourne shells don't support shell functions at all, we don't -# even define any local functions. - -# This script has been generalized to the point that it can now "start" -# any combination of classes with the normal static main methods. -# You can supply invocation arguments to the -# TARGET_CLASS invocation, and can start as many other classes as you -# wish by using the INVOC_ADDL_ARGS setting (this includes running -# multiple HSQLDB Servers of various types). - -# Template config file can be obtained from the HyperSQL distribution. -# On the day I write this, I have it located at "sample/hsqldb.cfg" in the -# distro, but that could change. You need to copy then edit it before it -# will work. -# Recommended locations for runtime configuration file: -# Darwin, SunOS, Solaris: /etc/hsqldb.conf -# (However, Sunfreeware.com builds use /usr/local/etc). -# Linux: /etc/hsqldb/hsqldb.conf (works well to put sqltool.rc here too) -# FreeBSD: /usr/local/etc/hsqldb.cfg -# (Replace the base name "hsqldb" with whatever you have SERVICE set to at -# the top of this file). -# You can put it at any of these locations and it will be used. For -# your sanity, only put a file at one of these locations. - -# -- blaine.simpson@admc.com - -set +u - -# Following function is Copyright Apache 2.0 by Axis Data Management Corp. -# and code is copied verbatim from -# http://pub.admc.com/scripts/bin/minsleep-nov.fnc -# Sleeps until process dies or file appears. -# 2nd parameter is assumed to be a PID if it is an integer. -minsleep() { - [ $# -eq 2 ] || { - echo 'SYNTAX: minsleep MAXSECS PID|PATH (for integers MAXSECS and PID)' 1>&2 - return 2 - } - TARGET_PID= TARGET_PATH= - MAXSECS=$1; shift - case "$1" in *[!0-9]*) TARGET_PATH="$1";; *) TARGET_PID="$1";; esac; shift - _secs=0 - while [ $_secs -lt $MAXSECS ]; do - _secs=`expr $_secs + 1` - if [ -n "$TARGET_PID" ]; then - kill -0 $TARGET_PID > /dev/null 2>&1 || return 0 # Target proc died - elif [ -s "$TARGET_PATH" ]; then - return 0 # Target process died - fi - sleep 1 - done - return 1 # Timed out -} - -# This is only used for recursive invocations. -# Will not necessarily be set correctly at system bootup invocations -# (where it is sometimes invoked like "sh... /path/to/hsqldb start"), -# but, in those cases there will be no recursion. -INVOC_PATH=`dirname "$0"` || { - echo "'dirname' failed" 1>&2 - exit 2 -} -[ -n "$INVOC_PATH" ] && INVOC_PATH="${INVOC_PATH}/" - -SYNTAX_MSG="SYNTAX: ${INVOC_PATH}${SERVICE} start|stop|stopcompact|restart|restartcmpacted|status" - -# You can override any of these default values in your config file: - -# Max time for background su command to start up and echo pid. -# (0 works for moderately fast servers). -SU_ECHO_SECS=30 -# File used as semaphore. If file is removed, a running pid checker -# process will exit. -PIDCHECKER_FLAGFILE=/tmp/pidchecker.run -# The following settings get overridden by optional setting in the config file. -# Max time for JVM to die after all HSQLDB instances stopped. -MAX_TERMINATE_SECS=60 -# We require all Server/WebServer instances to be accessible within -# $MAX_START_SECS from when the Server/WebServer is started. -MAX_START_SECS=60 -# Class to start -TARGET_CLASS=org.hsqldb.server.Server - -CLIENT_JVMARGS= -SERVER_JVMARGS= -CFGFILE= -LOGFILE= -PIDFILE= -BASEDIR= -AUTH_FILE= -SHUTDOWN_OPTION= -SERVER_ADDL_CLASSPATH= -INVOC_ADDL_ARGS= -case "`uname`" in - Darwin) # I.e. Mac OS X. I don't know about older Mac OSes. - LOGFILE=/var/log/${SERVICE}.log - PIDFILE=/var/run/${SERVICE}.pid - ;; - Linux) - LOGFILE=/var/log/${SERVICE}.log - PIDFILE=/run/${SERVICE}.pid - ;; - FreeBSD) - LOGFILE=/var/log/${SERVICE}.log - PIDFILE=/var/run/${SERVICE}.pid - ;; - SunOS) - LOGFILE=/var/log/${SERVICE}.log - PIDFILE=/etc/${SERVICE}.pid - ;; - *) - LOGFILE=/var/log/${SERVICE}.log - PIDFILE=/etc/${SERVICE}.pid - ;; -esac - -for candidate in /etc/hsqldb/${SERVICE}.conf \ - /etc/sysconfig/${SERVICE} /etc/${SERVICE}.conf \ - /etc/${SERVICE}.cfg /Library/Hsqldb/conf/${SERVICE}.cfg \ - /Library/Hsqldb/${SERVICE}.cfg /usr/local/etc/${SERVICE}.cfg; do - [ -f $candidate ] && { - CFGFILE=$candidate - break - } -done -[ -n "$CFGFILE" ] || { - echo "No global config file found in any of allowed locations" 1>&2 - exit 11 -} - -# Sanity check -[ -n "$LOGFILE" ] && [ -n "$PIDFILE" ] || { - echo "Internal problem in init script" 1>&2 - exit 11 -} - -[ $# -eq 1 ] || { - echo "$SYNTAX_MSG" 1>&2 - exit 4 -} - -# It would be nice to permit some uses, like "status" by non-root users, -# but for now our goal is a superuser init script. -[ -w / ] || { # Very portable, but perhaps not perfect, test for superuser. - echo "Only 'root' may use this init script" 1>&2 - exit 4 -} - -# Use bsd-style enable/disable if it's in place. -BSDCFG= -[ -r /etc/rc.conf ] && [ -f /etc/rc.conf ] && { - . /etc/rc.conf - BSDCFG=1 -} -[ -r /etc/rc.conf.local ] && [ -f /etc/rc.conf.local ] && { - . /etc/rc.conf.local - BSDCFG=1 -} -[ -n "$BSDCFG" ] && { - case "$hsqldb_enable" in [Yy][Ee][Ss]);; [Oo][Nn]);; [Tt][Rr][Uu][Ee]);; - *) exit 0;; # Don't run if not enabled for BSD startup - esac -} - -COMMAND="$1"; shift - -[ -r "$CFGFILE" ] || { - echo "Unable to read config file '$CFGFILE'" 1>&2 - exit 2 -} -[ -f "$CFGFILE" ] || { - echo "'$CFGFILE' is not a regular file" 1>&2 - exit 2 -} -HSQLDB_OWNER= -JAVA_EXECUTABLE= -SQLTOOL_JAR_PATH= -SERVER_HOME= -SHUTDOWN_URLIDS= -URLIDS= -. "$CFGFILE" -# Suffix delimiter to $SERVER_ADDL_CLASSPATH, if it is set. -[ -n "$SERVER_ADDL_CLASSPATH" ] && -SERVER_ADDL_CLASSPATH="${SERVER_ADDL_CLASSPATH}:" -# Validate that config file sets all required variables. -[ -n "$JAVA_EXECUTABLE" ] && [ -n "$SQLTOOL_JAR_PATH" ] && -[ -n "$SERVER_HOME" ] && [ -n "$URLIDS" ] || { - echo "Config file '$CFGFILE' does not set one or more of following variables - JAVA_EXECUTABLE, SQLTOOL_JAR_PATH, SERVER_HOME, URLIDS" 1>&2 - exit 2 -} -[ -d "$SERVER_HOME" ] || { - echo "SERVER_HOME variable in '$CFGFILE' is set to a non-directory." 1>&2 - exit 2 -} -[ -f "$JAVA_EXECUTABLE" ] && [ -f "$SQLTOOL_JAR_PATH" ] || { - echo "JAVA_EXECUTABLE or SQLTOOL_JAR_PATH in '$CFGFILE' is set to a non-file." 1>&2 - exit 2 -} - -[ -r "$SQLTOOL_JAR_PATH" ] || { - echo "'$SQLTOOL_JAR_PATH' isn't readable" 1>&2 - exit 2 -} -[ -x "$JAVA_EXECUTABLE" ] || { - echo "No Java executable found at '$JAVA_EXECUTABLE'" 1>&2 - exit 2 -} - -# "chown" lives here on some UNIXes. -PATH="$PATH:/usr/sbin" - -# Make a good effort (but not bullet-proof) check on permissions of the -# auth file. Unfortunately, if auth-file is not specified, this depends -# upon both (a) $HOME being set; and (b) SqlToolSprayer and SqlTool defaults. -# On the other hand, it works great if AUTH_FILE is set explicitly by user. -if [ -z "$AUTH_FILE" ] && [ -z "$HOME" ]; then - : # Lousy init environment didn't set $HOME, so can't find dflt cfg file. -else - _AUTH_TEST_PATH="$AUTH_FILE" - [ -n "${_AUTH_TEST_PATH}" ] || _AUTH_TEST_PATH="$HOME/sqltool.rc" - [ -f "$_AUTH_TEST_PATH" ] || { - echo "No auth file found at '$_AUTH_TEST_PATH'" 1>&2 - exit 2 - } - [ -r "$_AUTH_TEST_PATH" ] || { - echo "Auth file '$_AUTH_TEST_PATH' not readable" 1>&2 - exit 2 - } - ls -lLd "$_AUTH_TEST_PATH" | grep '^-..------' > /dev/null 2>&1 || { - echo "Fix permissions on '$_AUTH_TEST_PATH' like 'chmod 600 $_AUTH_TEST_PATH'" 1>&2 - exit 2 - } -fi - -# Set HSQLDB_PID according to pid file. -HSQLDB_PID= -[ -r "$PIDFILE" ] && { - [ -f "$PIDFILE" ] || { - echo "'$PIDFILE' is not a regular file" 1>&2 - exit 6 - } - [ -w "$PIDFILE" ] || { - echo "'$PIDFILE' is not writable" 1>&2 - exit 6 - } - HSQLDB_PID="`cat $PIDFILE`" || { - echo "Failed to read pid file '$PIDFILE'" 1>&2 - exit 6 - } - case "$HSQLDB_PID" in - *[a-zA-Z/!@#$%*+=_~]*) HSQLDB_PID=;; - *'^'*) HSQLDB_PID=;; - esac - [ -n "$HSQLDB_PID" ] || { - echo "Pid file '$PIDFILE' does not contain a valid process identifier" 1>&2 - exit 6 - } - kill -0 "$HSQLDB_PID" > /dev/null 2>&1 || { - echo 'Removing stale pid file' - rm -f "$PIDFILE" || { - echo "Failed to remove pid file '$PIDFILE'" 1>&2 - exit 6 - } - HSQLDB_PID= - } - #echo "PID is ($HSQLDB_PID)" -} - -case "$COMMAND" in - status) - [ -n "$HSQLDB_PID" ] || { - echo "I don't know of any running ${SERVICE} server." - exit 0 - } - echo "There is an ${SERVICE} server loaded from $SQLTOOL_JAR_PATH -running with pid $HSQLDB_PID." - # I would give a nice ps command here, were ps not so damned - # OS-specific. - AUTH_FILE_SWITCH= - # N.b., there will be a problem if there are special characters or - # spaces inside of $AUTH_FILE. - [ -n "$AUTH_FILE" ] && - AUTH_FILE_SWITCH="-Dsqltoolsprayer.rcfile=$AUTH_FILE" - # Might as well set CLASSPATH for a cleaner command. - CLASSPATH="$SQLTOOL_JAR_PATH" - export CLASSPATH - export PATH # Required only for some funny init environments. - exec "$JAVA_EXECUTABLE" $AUTH_FILE_SWITCH $CLIENT_JVMARGS \ - "-Dsqltoolsprayer.monfile=$PIDFILE" \ - org.hsqldb.cmdline.SqlToolSprayer 'CALL true;' $URLIDS > /dev/null - ;; - start) - [ -n "$TLS_KEYSTORE" ] || [ -n "$TLS_PASSWORD" ] && - echo "WARNING: The TLS_* settings have been obsoleted. -See the comments in the new sample 'hsqldb.cfg' file." 1>&2 - [ -n "$HSQLDB_PID" ] && { - echo "There is already a ${SERVICE} server running with pid $HSQLDB_PID." 1>&2 - exit 1 - } - if [ -n "$HSQLDB_OWNER" ]; then - touch "$PIDFILE" || { - echo "Failed to create pid file" 1>&2 - exit 1 - } - chown "$HSQLDB_OWNER" "$PIDFILE" || { - echo "Failed to chown pid file to '$HSQLDB_OWNER'" 1>&2 - exit 1 - } - # Some OSes choke if there are newlines in this string. - # N.b.!!! The shell of the -c command is the target user's default - # login shell, so keep this command shell-independent! - nohup su "$HSQLDB_OWNER" -c "cd '$SERVER_HOME' && echo "'$$'" > '$PIDFILE' && exec '$JAVA_EXECUTABLE' $SERVER_JVMARGS -classpath '${SERVER_ADDL_CLASSPATH}${SQLTOOL_JAR_PATH}' org.hsqldb.util.MainInvoker $TARGET_CLASS $INVOC_ADDL_ARGS" >> "$LOGFILE" 2>&1 & - else - cd "$SERVER_HOME" || { - echo "Failed to cd to '$SERVER_HOME'" 1>&2 - exit 1 - } - export JAVA_EXECUTABLE - export SQLTOOL_JAR_PATH - export PIDFILE - export SERVER_JVMARGS - export TARGET_CLASS - export INVOC_ADDL_ARGS - export SERVER_ADDL_CLASSPATH - nohup sh -c ' - echo $$ > "$PIDFILE" || { - echo "Failed to write pid to pid file" 1>&2 - exit 1 - } - eval exec "$JAVA_EXECUTABLE" $SERVER_JVMARGS -classpath "${SERVER_ADDL_CLASSPATH}${SQLTOOL_JAR_PATH}" org.hsqldb.util.MainInvoker $TARGET_CLASS $INVOC_ADDL_ARGS - ' >> "$LOGFILE" 2>&1 & - fi - minsleep $SU_ECHO_SECS "$PIDFILE" - # Make sure bg commands have time to echo pid. - AUTH_FILE_SWITCH= - # N.b., there will be a problem if there are special characters or - # spaces inside of $AUTH_FILE. - [ -n "$AUTH_FILE" ] && - AUTH_FILE_SWITCH="-Dsqltoolsprayer.rcfile=$AUTH_FILE" - # Might as well set CLASSPATH for a cleaner command. - CLASSPATH="$SQLTOOL_JAR_PATH" - export CLASSPATH - export PATH # Required only for some funny init environments. - # There are many reasons why we could fail to read the pid file, - # but regardless of why, the pid file does not contain a valid pid. - touch "$PIDCHECKER_FLAGFILE" || { - echo "Failed to touch file '$PIDCHECKER_FLAGFILE'" 1>&2 - exit 1 - } - export PIDCHECKER_FLAGFILE - export PIDFILE - ( - while true; do - # Could possibly use minsleep to simplify this, but I don't - # want to take the time to test the function export behavior. - # -a and -e tests are not portable. - [ -f "$PIDCHECKER_FLAGFILE" ] || exit 0 - kill -0 "`cat $PIDFILE`" > /dev/null 2>&1 || { - rm -f "$PIDFILE" "$PIDCHECKER_FLAGFILE" - exit 1 - } - sleep 1 - done - ) & - "$JAVA_EXECUTABLE" $AUTH_FILE_SWITCH $CLIENT_JVMARGS \ - "-Dsqltoolsprayer.monfile=$PIDFILE" \ - "-Dsqltoolsprayer.maxtime=${MAX_START_SECS}000" \ - org.hsqldb.cmdline.SqlToolSprayer 'CALL true;' $URLIDS > /dev/null && { - rm -f "$PIDCHECKER_FLAGFILE" - echo "$TARGET_CLASS started with pid `cat $PIDFILE`" - exit 0 - } - rm -f "$PIDCHECKER_FLAGFILE" - echo "Failed to start $TARGET_CLASS. -See log file '$LOGFILE'." 1>&2 - exit 1 - ;; - stop|stopcompact) - [ "$COMMAND" = stopcompact ] && SHUTDOWN_OPTION='compact' - [ -n "$HSQLDB_PID" ] || { - echo "I don't know of any running ${SERVICE} server." 1>&2 - exit 1 - } - AUTH_FILE_SWITCH= - # N.b., there will be a problem if there are special characters or - # spaces inside of $AUTH_FILE. - [ -n "$AUTH_FILE" ] && - AUTH_FILE_SWITCH="-Dsqltoolsprayer.rcfile=$AUTH_FILE" - # Might as well set CLASSPATH for a cleaner command. - CLASSPATH="$SQLTOOL_JAR_PATH" - export CLASSPATH - export PATH # Required only for some funny init environments. - "$JAVA_EXECUTABLE" $AUTH_FILE_SWITCH $CLIENT_JVMARGS \ - org.hsqldb.cmdline.SqlToolSprayer "shutdown ${SHUTDOWN_OPTION};" \ - $URLIDS $SHUTDOWN_URLIDS || exit 1 - minsleep $MAX_TERMINATE_SECS $HSQLDB_PID || { - echo "WARNING: ${SERVICE} is still running!" 1>&2 - exit 1 - } - rm -f "$PIDFILE" || { - echo "Failed to remove pid file '$PIDFILE'" 1>&2 - exit 1 - } - echo "Successful shutdown ${SHUTDOWN_OPTION} (for the $TARGET_CLASS process)!" - exit 0 - ;; - restart|restartcompacted) - STOP_COMMAND=stop - [ "$COMMAND" = restartcompacted ] && STOP_COMMAND=stopcompact - "${INVOC_PATH}"${SERVICE} $STOP_COMMAND || exit $? - exec "${INVOC_PATH}"/${SERVICE} start - ;; - *) - echo "$SYNTAX_MSG" 1>&2 - exit 5 - ;; -esac diff --git a/database/hsqldb/sample/hsqldb.service b/database/hsqldb/sample/hsqldb.service deleted file mode 100644 index 6fb9e3c6..00000000 --- a/database/hsqldb/sample/hsqldb.service +++ /dev/null @@ -1,34 +0,0 @@ -# $Id: hsqldb.service 6309 2021-02-28 15:06:19Z unsaved $ - -# This file is a systemd init script wrapper for leading-edge UNIXes. -# Copy $HSQLDB_HOME/.../sample/hsqldb.cfg to /etc/hsqldb.conf and edit it. -# Tend to the "TODO" note below. -# Our init script will fail unless your .rc file is protected something like: -# chmod 0600 /path/to/sqltool.rc -# -# To activate this file, run: systemd daemon-reload -# To enable to execute upon system bootups/shutdowns (the ultimate purpose), run: -# systemctl enable hsqldb -# -# -- Blaine (blaine dot simpson at admc dot com) - -[Unit] -Description=HyperSQL Database Server -After=socket.service - -[Service] -# TODO! Change these paths to point to the absolute path of the "hsqldb.init" -# script in your HyperSQL distribution: -ExecStart=/local/hsqldb-2.3.4/sample/hsqldb.init start -ExecReload=/local/hsqldb-2.3.4/sample/hsqldb.init restart -ExecStop=/local/hsqldb-2.3.4/sample/hsqldb.init stop -KillMode=process -#Restart=always Don't silently restart and mask real problems -PIDFile=/run/hsqldb.pid -#User=... We manage user from file /etc/hsqldb.conf -#WorkingDirectory=... No dependency on $PWD -Type=forking -TimeoutStartSec=10 - -[Install] -WantedBy=multi-user.target diff --git a/database/hsqldb/sample/html-report.sql b/database/hsqldb/sample/html-report.sql deleted file mode 100644 index 0cb9bbe9..00000000 --- a/database/hsqldb/sample/html-report.sql +++ /dev/null @@ -1,54 +0,0 @@ -/* - * $Id: html-report.sql 4512 2011-10-11 02:29:08Z unsaved $ - * - * Sample/Template for writing an HTML Report - */ - --- Populate sample data -create table t (i integer, vc varchar(20)); -insert into t values(1, 'one'); -insert into t values(2, 'two'); -insert into t values(3, 'three'); -insert into t values(4, 'four'); -insert into t values(5, 'five'); -commit; - - --- IMPORTANT: \o will append by default. If you want to write a new file, --- it's your responsibility to check that a file of the same name does not --- already exist (or remove it). - - --- Follow the following examples to use your own HTML fragment files. --- * *TOP_HTMLFRAG_FILE = /tmp/top.html --- * *BOTTOM_HTMLFRAG_FILE = /tmp/bottom.html - --- The default TOP_HTMLFRAG_FILE has a reference to this PL variable. -* REPORT_TITLE = Blaine's Sample Report --- The default will also override its CSS style settings with your own if you --- put them in a file named "overrides.css" in same directory alongside your --- reports ("report.html" in this example). --- You can add references to ${system.properties} and *{PL_VARIABLES} in --- your own custom fragment files too. - - --- Turn on HTML output mode. --- Must enable HTML _before_ opening to write top frag. -\h true -\o report.html -\p A message to appear in the Report -SELECT * FROM t; - --- Close off output just to show that you can go back and forth. --- A close with '\o' will not write the bottom boilerplate that closes the HTML. -\o -\h false -\p Some non-HTML non-Report output: -SELECT count(*) FROM t; - -\h true --- Re-open the report -\o report.html -\d t --- This time close it with -\oc diff --git a/database/hsqldb/sample/j-sample.sql b/database/hsqldb/sample/j-sample.sql deleted file mode 100644 index a084d178..00000000 --- a/database/hsqldb/sample/j-sample.sql +++ /dev/null @@ -1,38 +0,0 @@ -/* - $Id: j-sample.sql 3605 2010-06-01 02:21:36Z unsaved $ - Exemplifies use of SqlTool's \j command to specify the JDBC connection - parameters right in the SQL file. - - Invoke like this: - - java -jar .../sqltool.jar - .../j-sample.sql - - (give the file paths to wherever these two files reside). - Or start up SqlTool like this: - - java -jar .../sqltool.jar - - and then execute this script like - - \i .../j-sample.sql -*/ - --- Abort this script when errors occur. --- That's the default if the script is invoked from command-line, but not if --- invoked by \i. -\c false - --- Note the new feature in HyperSQL 2, whereby you can set an SA password --- by just specifying that as the password for the very first connection to --- that database -\j SA fred jdbc:hsqldb:mem:fred --- FORMAT: \j - -\p You have conkected successfully -\p - -CREATE TABLE t(i BIGINT, vc VARCHAR(20)); -INSERT INTO t VALUES(1, 'one'); -INSERT INTO t VALUES(2, 'two'); - -SELECT * FROM t; diff --git a/database/hsqldb/sample/jaas.cfg b/database/hsqldb/sample/jaas.cfg deleted file mode 100644 index cf4d8064..00000000 --- a/database/hsqldb/sample/jaas.cfg +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright (c) 2010, The HSQL Development Group. All rights reserved. - Released under the HSQL license, available at http://hsqldb.org - - This is a working JAAS configuration file that sets up two "applications" - for use with HyperSQL's extAuthWithSpring sample. - Look under /integration/extAuthWithSpring in your HyperSQL distribution for - details. -*/ - -demo { - /* - * A trivial module that allows access if user name and password start with - * the specified values. - * See source code for the module in for this class under the test-src - * directory of your HyperSQL installation. - */ - org.hsqldb.auth.StartCharModule required - //debug=true - nameStart="s" - pwdStart="p" - ; -}; - -sunLdap { - /* - * JAAS setup for com.sun.security.auth.module.LdapLoginModule. - * This proprietary Sun Java 1.6 JSSE module doesn't support StartTLS, but - * does support the deprecated LDAPS. It also supports only a single role or - * initial schema. - * Do a web search for LdapLoginModule for the API Spec which describes the - * available settings and (incompletely) functionality. There is another - * popular class on the Internet with the same name, so make sure you look at - * the one with package of com.sun.security.auth.module. - */ - com.sun.security.auth.module.LdapLoginModule required - // useSSL means LDAPS, not StartDLS (which is not supported). - // It is true by default, so set to false unless you want LDAPS. - useSSL=false - // Enable following line for debugging - // debug=true - java.naming.security.authentication="DIGEST-MD5" - // Your URL must include the parent DN for user records as shown. - userProvider="ldap://beyla.admc.com/ou=people,dc=admc,dc=com" - authIdentity="{USERNAME}" - userFilter="uid={USERNAME}" - authzIdentity="{memberof}" - ; -}; diff --git a/database/hsqldb/sample/ldap-exerciser.properties b/database/hsqldb/sample/ldap-exerciser.properties deleted file mode 100644 index 95406488..00000000 --- a/database/hsqldb/sample/ldap-exerciser.properties +++ /dev/null @@ -1,44 +0,0 @@ -# $Id: ldap-exerciser.properties 3872 2010-11-09 04:14:40Z unsaved $ - -# This is a sample properties file for the utility program -# org.hsqldb.auth.LdapAuthBean. See the API Spec for -# org.hsqldb.auth.LdapAuthBean for details about all of the settings you can use -# here. - -# IMPORTANT: Use ISO-8859-1 encoding for any extended characters, as you always -# should for a Java properties file. - -# The ${...} construct (for system properties) is not supported. - -# All of these examples use a roleSchemaValuePattern setting to work with the -# LDAP memberOf feature. If you have a direct attribute for specifying roles -# (and optional schema), then just skip that setting. - -# These settings are used for all sample setups -# When startTls is true, ldapHost must match the CN in the server's cert. -ldapHost=beyla.admc.com -parentDn=ou=people,dc=admc,dc=com -roleSchemaValuePattern=cn=([^,]+).* -rolesSchemaAttribute=memberof -accessAttribute=hyperSqlAccess - -# This block of settings works for an OpenLDAP server using the memberOf -# feature for membership in roles, with DIGEST-MD5 SASL and StartTLS with a -# private (non-commercial) SSL certificate. -startTls=true -trustStore=/home/blaine/ca/cacert.store -securityMechanism=DIGEST-MD5 - -# To use an LDAP server that is totally unsecured, comment out the settings in -# the previous block and enable the one setting here. -# An unsecured server can be useful for educational purposes, but not for a -# real application! -#principalTemplate=uid=${username},ou=people,dc=admc,dc=com - -# PLAIN authentication, but StartTLS-encrypted. Disable the block above -# starting with "startTls=true" and enable the settings in this block. -#principalTemplate=uid=${username},ou=people,dc=admc,dc=com - -# SASL DIGEST-MD5 with no encryption. Disable the block above -# starting with "startTls=true" and enable the settings in this block. -#securityMechanism=DIGEST-MD5 diff --git a/database/hsqldb/sample/load_binding_lu.sql b/database/hsqldb/sample/load_binding_lu.sql deleted file mode 100644 index 13be042f..00000000 --- a/database/hsqldb/sample/load_binding_lu.sql +++ /dev/null @@ -1,31 +0,0 @@ -/* - $Id: load_binding_lu.sql 610 2008-12-22 15:54:18Z unsaved $ - Load BINDING Lookup Text Table -*/ - -\p Creating table BINDING_TMPTXT -CREATE TEMP TEXT TABLE binding_tmptxt ( - id integer, - name varchar(12) -); - -\p Setting text file source -SET TABLE binding_tmptxt SOURCE "binding_lu.ttbl;ignore_first=true;fs=|"; - -\p rows in binding_tmptxt: -select count(*) from binding_tmptxt; -\p PRE rows in binding_lu: -select count(*) from binding_lu; - -INSERT INTO binding_lu ( - id, - name -) SELECT - id, - name -FROM BINDING_TMPTXT; - -commit; - -\p POST rows in binding_lu: -select count(*) from binding_lu; diff --git a/database/hsqldb/sample/nullempty.sql b/database/hsqldb/sample/nullempty.sql deleted file mode 100644 index 70c50240..00000000 --- a/database/hsqldb/sample/nullempty.sql +++ /dev/null @@ -1,33 +0,0 @@ -/* - * $Id: nullempty.sql 4709 2011-11-05 01:50:17Z unsaved $ - * - * This sample shows differences between null and empty strings, - * and ? var vs. _/~ variables. - */ - -\p At startup ? is equal to empty string. See between A and B: A*{?}B -* if (A*{?}B == AB) \p ? is the empty string - -CREATE TABLE t(i INTEGER, vc VARCHAR(20)); -INSERT INTO t VALUES(1, 'one'); -INSERT INTO t VALUES(2, 'two'); -* res ~ -SELECT * FROM t; -\p *{?} -\p *{res} -* listvalues ? res - -INSERT INTO t VALUES (3, null); -*res ~ -SELECT vc FROM t WHERE i = 3; -\p *{?} -* if (*res == **NULL) \p res really is null -* listvalues ? res - --- This will prevent SqlTool from aborting when we run a bad SQL statement: -\c true -*res ~ -SELECT hocus FROM pocus; -* if (*? == **NULL) \p ? really is null -* if (*res == **NULL) \p res really is null -* listvalues ? res diff --git a/database/hsqldb/sample/pl.sql b/database/hsqldb/sample/pl.sql deleted file mode 100644 index 3ce8c327..00000000 --- a/database/hsqldb/sample/pl.sql +++ /dev/null @@ -1,95 +0,0 @@ -/* - $Id: pl.sql 4563 2011-10-19 02:24:41Z unsaved $ - SQL File to illustrate the use of some basic SqlTool PL features. - Invoke like - java -jar .../sqltool.jar mem .../pl.sql - -- blaine -*/ - -* if (! *MYTABLE) - \p MYTABLE variable not set! - /* You could use \q to Quit SqlTool, but it's often better to just - break out of the current SQL file. - If people invoke your script from SqlTool interactively (with - \i yourscriptname.sql) any \q will kill their SqlTool session. */ - \p Use argument "-pMYTABLE=mytablename" for SqlTool - * break -* end if - --- Turning on Continue-upon-errors so that we can check for errors ourselves. -\c true - -\p -\p Loading up a table named '*{MYTABLE}'... - -CREATE TABLE *{MYTABLE} ( - i int, - s varchar(20) -); --- PL variable ? is always set to status or fetched value of last SQL --- statement. It will be null/unset if the last SQL statement failed. -\p CREATE status is *{?} -\p - -/* Validate our return status. - In case of success of a CREATE TABLE, *? will be 0, and therefore a - '* if (*?)' would be false. - So we follow the general practice of testing *? for the error indicator - value of null, using the reserved SqlTool system variable *NULL. - */ -* if (*? == *NULL) - \p Our CREATE TABLE command failed. - * break -* end if - --- Default Continue-on-error behavior is what you usually want -\c false -\p - -/* Insert data with a foreach loop. - These values could be from a read of another table or from variables - set on the command line like -*/ -\p Inserting some data into our new table -* foreach VALUE (12 22 24 15) - * if (*VALUE > 23) - \p Skipping *{VALUE} because it is greater than 23 - * continue - \p YOU WILL NEVER SEE THIS LINE, because we just 'continued'. - * end if - INSERT INTO *{MYTABLE} VALUES (*{VALUE}, 'String of *{VALUE}'); -* end foreach -\p - -/* This time instead of using the ? variable, we're assigning the SELECT value - to a User variable, 'themax'. */ -* themax ~ -/* Can put Special Commands and comments between "* VARNAME ~" and the target - SQL statement. */ -\p We're saving the max value for later. You'll still see query output here: -SELECT MAX(i) FROM *{MYTABLE}; - -/* No need to test for failure status (either ? or themax being unset/null), - because we are in \c mode and would have aborted if the SELECT failed. */ -* if (0 == *themax) - \p Got 0 as the max value. - * break - \p YOU WILL NEVER SEE THIS LINE, because we just 'broke'. -* end if - -\p -\p ############################################################## -\p The results of our work: -SELECT * FROM *{MYTABLE}; -\p MAX value is *{themax} - -\p -\p Counting down to exit -* ((i = 3)) -* while (*i > 0) - \p *{i}... - * ((i -= 1)) -- i++ is supported but i-- is not, because -- marks comments -* end while - -\p -\p Everything worked. Signing off. diff --git a/database/hsqldb/sample/plsql.sql b/database/hsqldb/sample/plsql.sql deleted file mode 100644 index 5318697e..00000000 --- a/database/hsqldb/sample/plsql.sql +++ /dev/null @@ -1,44 +0,0 @@ -/* - * $Id: plsql.sql 6375 2021-11-07 17:44:56Z unsaved $ - * - * This example is copied from the "Simple Programs in PL/SQL" - * example by Yu-May Chang, Jeff Ullman, Prof. Jennifer Widom at - * the Standord University Database Group's page - * http://www-db.stanford.edu/~ullman/fcdb/oracle/or-plsql.html . - * I have only removed some blank lines (in case somebody wants to - * copy this code interactively-- because you can't use blank - * lines inside of SQL commands in non-raw mode SqlTool when running - * it interactively); and, at the bottom I have replaced the - * client-specific, non-standard command "run;" with SqlTool's - * corresponding command ".;" and added a plain SQL SELECT command - * to show whether the PL/SQL code worked. - Blaine - */ - -CREATE TABLE T1( - e INTEGER, - f INTEGER -); - -DELETE FROM T1; - -INSERT INTO T1 VALUES(1, 3); - -INSERT INTO T1 VALUES(2, 4); - -/* Above is plain SQL; below is the PL/SQL program. */ -DECLARE - a NUMBER; - b NUMBER; -BEGIN - SELECT e,f INTO a,b FROM T1 WHERE e>1; - INSERT INTO T1 VALUES(b,a); -END; -.; -/** The statement on the previous line, ".;" is SqlTool specific. - * This command says to save the input up to this point to the - * edit buffer and send it to the database server for execution. - * I added the SELECT statement below to give imm - */ - -/* This should show 3 rows, one containing values 4 and 2 (in this order)...*/ -SELECT * FROM t1; diff --git a/database/hsqldb/sample/sample.c b/database/hsqldb/sample/sample.c deleted file mode 100644 index dacc5c4f..00000000 --- a/database/hsqldb/sample/sample.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * @(#)$Id: sample.c 3648 2010-06-08 22:44:25Z unsaved $ - * - * HyperSQL Database Engine - * - * Copyright (c) 2009-2010, The HSQL Development Group - */ - - -#include -#ifdef _WINDOWS -#include -#endif -#include -// sqlext.h pulls in all other ODBC header files that we need -#include -#include - -extern int detectOdbcFailure(SQLRETURN rv, SQLHENV c, char* failMsg); -extern int print_ret(char* msg, int retval); -extern int print2_ret(char* msg, char* msg2, int retval); - -/** - * This test HyperSQL client uses the ODBC DSN "tstdsn" to connect up to a - * HyperSQL server. Just configure your own DSN to use the HyperSQL ODBC - * driver, specifying the HyperSQL server host name, database name, user, - * password, etc. - * - * Sample C program accessing HyperSQL. - * - * ODBC C API ref at - * http://msdn.microsoft.com/en-us/library/ms714562(VS.85).aspx . - * Summary of functions at - * http://msdn.microsoft.com/en-us/library/ms712628(VS.85).aspx - * - * To build on UNIX with unixODBC:

- *     gcc -lodbc -o sample sample.c
- * 
- * - * To build in Windows with MSVC++ (Express variant is free):

- *      cl /nologo /D _WINDOWS /D ODBCVER=0x0351 /c sample.c
- *      link odbc32.lib /nologo /machine:x86 sample.obj /out:sample.exe
- * 
- * - * @author Blaine Simpson (blaine dot simpson at admc dot com) - */ -int main(int argc, char** argv) { - SQLRETURN odbcret; - SQLHENV sqlhenv; - SQLHENV conn; - SQLHSTMT stmt; - char *cp; - long in_idval; - const int cstrmax = 100; - char *in_vcval = malloc(cstrmax); - long out_idval; - char *out_vcval = malloc(cstrmax); - char *out_etimeval = malloc(cstrmax); - SQLLEN ntsval = SQL_NTS; - int detect; - - // I. CONNECT - odbcret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlhenv); - if (odbcret != SQL_SUCCESS && odbcret != SQL_SUCCESS_WITH_INFO) - return print_ret("Failed to allocate an ODBC environment handle", 1); - - odbcret = - SQLSetEnvAttr(sqlhenv, SQL_ATTR_ODBC_VERSION, (void*) SQL_OV_ODBC3, 0); - if (odbcret != SQL_SUCCESS && odbcret != SQL_SUCCESS_WITH_INFO) - return print_ret("Failed to set ODBC version 3.0", 2); - - odbcret = SQLAllocHandle(SQL_HANDLE_DBC, sqlhenv, &conn); - if (odbcret != SQL_SUCCESS && odbcret != SQL_SUCCESS_WITH_INFO) - return print_ret("Failed to allocate an ODBC connection handle", 3); - - odbcret = SQLSetConnectAttr( - conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, 0); - if (odbcret != SQL_SUCCESS && odbcret != SQL_SUCCESS_WITH_INFO) - return print_ret("Failed to allocate an ODBC connection handle", 3); - // May also want to set timeout values in the same way - - // Can override the DSN-defined user name and/or password here: - detect = detectOdbcFailure( - SQLConnect(conn, (SQLCHAR*) "tstdsn", SQL_NTS, (SQLCHAR*) NULL, 0, - (SQLCHAR*) NULL, 0), - conn, "Connection failure"); - if (detect) return detect; - - - // II. PREPARE OBJECTS FOR USE - detect = detectOdbcFailure( - SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt), conn, - "Failed to allocate an ODBC statement handle"); - if (detect) return detect; - - // Just using this char pointer because some non-ANSI compilers won't let - // us declare a char array/pointer here. - cp = "DROP TABLE tsttbl IF EXISTS"; - detect = detectOdbcFailure(SQLExecDirect(stmt, cp, SQL_NTS), conn, - "DROP statement failed"); - if (detect) return detect; - - // Some recent change to the HyperSQL server or to unixODBC - // has made this commit necessary, at least on UNIX. Some other - // transaction control command would probably be more - // appropriate here. - detect = detectOdbcFailure(SQLEndTran(SQL_HANDLE_DBC, conn, SQL_COMMIT), - conn, "COMMIT failed"); - if (detect) return detect; - - cp = "CREATE TABLE tsttbl(\n\ - id BIGINT generated BY DEFAULT AS IDENTITY,\n\ - vc VARCHAR(20),\n\ - entrytime TIMESTAMP DEFAULT current_timestamp NOT NULL\n\ -)"; - detect = detectOdbcFailure(SQLExecDirect(stmt, cp, SQL_NTS), conn, - "CREATE TABLE statement failed"); - if (detect) return detect; - - detect = detectOdbcFailure(SQLCloseCursor(stmt), conn, - "Failed to close Cursor for re-use"); - if (detect) return detect; - - - // III. INSERT DATA - // Non-parameter INSERT - cp = "INSERT INTO tsttbl (id, vc) values (1, 'one')"; - detect = detectOdbcFailure(SQLExecDirect(stmt, cp, SQL_NTS), conn, - "1st Insertion failed"); - if (detect) return detect; - -#ifdef _WINDOWS - // TODO: PROBLEM with Parameterized INPUT in Windows (works fine on UNIX). - // For some reason, even if we are do a Prepare/Execute (and our - // driver is set to always use server-side Preparation), the client side - // is doing the substitution... and doing a bad Lob of it too. - // Therefore, we do all INSERTs statically for Windows here: - cp = "INSERT INTO tsttbl (id, vc) values (2, 'two')"; - detect = detectOdbcFailure(SQLExecDirect(stmt, cp, SQL_NTS), conn, - "2nd Insertion failed"); - if (detect) return detect; - cp = "INSERT INTO tsttbl (id, vc) values (3, 'three')"; - detect = detectOdbcFailure(SQLExecDirect(stmt, cp, SQL_NTS), conn, - "3rd Insertion failed"); - if (detect) return detect; - cp = "INSERT INTO tsttbl (id, vc) values (4, 'four')"; - detect = detectOdbcFailure(SQLExecDirect(stmt, cp, SQL_NTS), conn, - "4th Insertion failed"); - if (detect) return detect; - cp = "INSERT INTO tsttbl (id, vc) values (5, 'five')"; - detect = detectOdbcFailure(SQLExecDirect(stmt, cp, SQL_NTS), conn, - "5th Insertion failed"); - if (detect) return detect; -#else - // Parameterized INSERT - cp = "INSERT INTO tsttbl (id, vc) values (?, ?)"; - detect = detectOdbcFailure(SQLPrepare(stmt, (SQLCHAR*) cp, SQL_NTS), conn, - "Preparation of Insertion stmt failed"); - if (detect) return detect; - detect = detectOdbcFailure( - SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, - 0, 0, &in_idval, 0, NULL), conn, - "Bind of 'id' input failed"); - if (detect) return detect; - detect = detectOdbcFailure( - SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, - 20, 0, in_vcval, cstrmax, &ntsval), conn, - "Bind of 'vc' input failed"); - if (detect) return detect; - - in_idval = 2; - strcpy(in_vcval, "two"); - detect = detectOdbcFailure(SQLExecute(stmt), conn, - "Insertion of 2nd row failed"); - if (detect) return detect; - in_idval = 3; - strcpy(in_vcval, "three"); - detect = detectOdbcFailure(SQLExecute(stmt), conn, - "Insertion of 3rd row failed"); - if (detect) return detect; - in_idval = 4; - strcpy(in_vcval, "four"); - detect = detectOdbcFailure(SQLExecute(stmt), conn, - "Insertion of 4th row failed"); - if (detect) return detect; - in_idval = 5; - strcpy(in_vcval, "five"); - detect = detectOdbcFailure(SQLExecute(stmt), conn, - "Insertion of 5th row failed"); - if (detect) return detect; -#endif - - detect = detectOdbcFailure(SQLEndTran(SQL_HANDLE_DBC, conn, SQL_COMMIT), - conn, "COMMIT failed"); - if (detect) return detect; - - detect = detectOdbcFailure(SQLCloseCursor(stmt), conn, - "Failed to close Cursor for re-use"); - if (detect) return detect; - - - // IV. QUERIES - // Non-Parameter QUERY - cp = "SELECT * FROM tsttbl WHERE id < 3"; - detect = detectOdbcFailure(SQLExecDirect(stmt, cp, SQL_NTS), conn, - "Non-parameter query failed"); - // Would return SQL_NO_DATA if no rows inserted. - // Don't need to bind until before fetches are performed. - if (detect) return detect; - detect = detectOdbcFailure( - SQLBindCol(stmt, 1, SQL_C_SLONG, &out_idval, 0, NULL), conn, - "Bind of 'id' output failed"); - if (detect) return detect; - detect = detectOdbcFailure( - SQLBindCol(stmt, 2, SQL_C_CHAR, out_vcval, cstrmax, &ntsval), - conn, "Bind of 'vc' output failed"); - if (detect) return detect; - detect = detectOdbcFailure( - SQLBindCol(stmt, 3, SQL_C_CHAR, out_etimeval, cstrmax, &ntsval), - conn, "Bind of 'entrytime' output failed"); - if (detect) return detect; - - while ((odbcret = SQLFetch(stmt)) != SQL_NO_DATA) { - if (detectOdbcFailure(odbcret, conn, "Fetch failed")) return detect; - printf("%dl|%s|%s\n", out_idval, out_vcval, out_etimeval); - } - - detect = detectOdbcFailure(SQLCloseCursor(stmt), conn, - "Failed to close Cursor for re-use"); - if (detect) return detect; - -#if _WINDOWS - // Input parameters not working on Windows. See comment above. - cp = "SELECT * FROM tsttbl WHERE id > 3"; - detect = detectOdbcFailure(SQLExecDirect(stmt, cp, SQL_NTS), conn, - "Non-parameter query failed"); - // Would return SQL_NO_DATA if no rows inserted. - // Don't need to bind until before fetches are performed. - if (detect) return detect; - detect = detectOdbcFailure( - SQLBindCol(stmt, 1, SQL_C_SLONG, &out_idval, 0, NULL), conn, - "Bind of 'id' output failed"); - if (detect) return detect; - detect = detectOdbcFailure( - SQLBindCol(stmt, 2, SQL_C_CHAR, out_vcval, cstrmax, &ntsval), - conn, "Bind of 'vc' output failed"); - if (detect) return detect; - detect = detectOdbcFailure( - SQLBindCol(stmt, 3, SQL_C_CHAR, out_etimeval, cstrmax, &ntsval), - conn, "Bind of 'entrytime' output failed"); - if (detect) return detect; - - while ((odbcret = SQLFetch(stmt)) != SQL_NO_DATA) { - if (detectOdbcFailure(odbcret, conn, "Fetch failed")) return detect; - printf("%dl|%s|%s\n", out_idval, out_vcval, out_etimeval); - } -#else - - // Parameterized QUERY - cp = "SELECT * FROM tsttbl WHERE id > ?"; - detect = detectOdbcFailure(SQLPrepare(stmt, (SQLCHAR*) cp, SQL_NTS), conn, - "Preparation of Query stmt failed"); - if (detect) return detect; - in_idval = 3; - detect = detectOdbcFailure( - SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, - 0, 0, &in_idval, 0, NULL), conn, - "Bind of 'id' input failed"); - if (detect) return detect; - detect = detectOdbcFailure(SQLExecute(stmt), conn, - "Parameterized query failed"); - // Would return SQL_NO_DATA if no rows selected - // Don't need to bind until before fetches are performed. - if (detect) return detect; - detect = detectOdbcFailure( - SQLBindCol(stmt, 1, SQL_C_SLONG, &out_idval, 0, NULL), conn, - "Bind of 'id' output failed"); - if (detect) return detect; - detect = detectOdbcFailure( - SQLBindCol(stmt, 2, SQL_C_CHAR, out_vcval, cstrmax, &ntsval), - conn, "Bind of 'vc' output failed"); - if (detect) return detect; - detect = detectOdbcFailure( - SQLBindCol(stmt, 3, SQL_C_CHAR, out_etimeval, cstrmax, &ntsval), - conn, "Bind of 'entrytime' output failed"); - if (detect) return detect; -#endif - - while ((odbcret = SQLFetch(stmt)) != SQL_NO_DATA) { - if (detectOdbcFailure(odbcret, conn, "Fetch failed")) return detect; - printf("%dl|%s|%s\n", out_idval, out_vcval, out_etimeval); - } - - detect = detectOdbcFailure(SQLCloseCursor(stmt), conn, - "Failed to close Cursor"); - if (detect) return detect; - - SQLDisconnect(conn); - SQLFreeHandle(SQL_HANDLE_DBC, conn); - SQLFreeHandle(SQL_HANDLE_ENV, sqlhenv); - //return print_ret("Success", 0); - return 0; -} - -/** - * Displays error message and prepare for program exit. - */ -int barf(SQLHENV c, char* failMsg) { - char sqlhmsg[200], sqlhstat[10]; - SQLSMALLINT junksmall; - SQLINTEGER errint; - - SQLGetDiagRec(SQL_HANDLE_DBC, c, 1, sqlhstat, &errint, - sqlhmsg, 100, &junksmall); - return print2_ret(failMsg, sqlhmsg, 1); -} - -/** - * Displays error message and prepare for program exit if the given - * rv indicates ODBC failure. - */ -int detectOdbcFailure(SQLRETURN rv, SQLHENV c, char* failMsg) { - if (rv == SQL_SUCCESS || rv == SQL_SUCCESS_WITH_INFO) return 0; - return barf(c, failMsg); -} - -/** - * 2-param wrapper for print2_ret() function. - */ -int print_ret(char* msg, int retval) { - return print2_ret(msg, (char*) NULL, retval); -} - -/** - * Displays message to stderr and returns given value. - * - * Function name here is a hack, because I don't remember how to overload C - * functions (in a portable way). - */ -int print2_ret(char* msg, char* msg2, int retval) { - fputs(msg, stderr); - fputc('\n', stderr); - if (msg2 != NULL) { - fputs(msg2, stderr); - fputc('\n', stderr); - } - return retval; -} diff --git a/database/hsqldb/sample/sample.dsv b/database/hsqldb/sample/sample.dsv deleted file mode 100644 index 4cea4715..00000000 --- a/database/hsqldb/sample/sample.dsv +++ /dev/null @@ -1,16 +0,0 @@ -# Comment lines like this are permitted by default, as are - -# blank lines. Header line follows: -i|d|b - -# Two good rows: -1|2007-01-02|true -2|2007-01-03|false - -# This should cause a parse error: -3|not a date|true - -# This should cause a database error: -4||true - -5|2007-01-04|false diff --git a/database/hsqldb/sample/sample.php b/database/hsqldb/sample/sample.php deleted file mode 100644 index d6fd84d7..00000000 --- a/database/hsqldb/sample/sample.php +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/php5 - diff --git a/database/hsqldb/sample/sample.pl b/database/hsqldb/sample/sample.pl deleted file mode 100644 index a51b2906..00000000 --- a/database/hsqldb/sample/sample.pl +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/perl - -# $Id: sample.pl 3633 2010-06-06 23:56:41Z unsaved $ - -# Sample Perl script accessing HyperSQL through the Perl DBI and DBD/ODBC -# modules. - -# This test HyperSQL client uses the ODBC DSN "tstdsn" to connect up to a -# HyperSQL server. Just configure your own DSN to use the HyperSQL ODBC -# driver, specifying the HyperSQL server host name, database name, user, -# password, etc. - -# Author: Blaine Simpson (blaine dot simpson at admc dot com) - - -use strict; -use DBI; - -use vars qw:$dsn $dbh $sth $row $retval %conAttr:; - -$conAttr{AutoCommit} = 0; - -# In addition to the DSN name, you can override or supply additional DSN -# settings, such as "Uid" and "Pwd"; or define the DSN from scratch, starting -# with Driver. These settings are delimited with "; ". See pyodbc docs. -$dsn = "dbi:ODBC:dsn=tstdsn"; - -#$dbh = DBI->connect($dsn, undef, undef) -$dbh = DBI->connect($dsn, undef, undef, \%conAttr) - or die("Failed to connect: ($DBI::err) $DBI::errstr\n"); - -$dbh->do("DROP TABLE tsttbl IF EXISTS"); -$dbh->do( - "CREATE TABLE tsttbl(\n" - . " id BIGINT generated BY DEFAULT AS IDENTITY,\n" - . " vc VARCHAR(20),\n" - . " entrytime TIMESTAMP DEFAULT current_timestamp NOT NULL\n" - . ")"); - -# First a simple/non-parameterized Insertion -$retval = $dbh->do("INSERT INTO tsttbl (id, vc) values (1, 'one')"); -die "First insertion inserted $retval rows instead of 1\n" unless $retval eq 1; - -# Now same thing with parameters -$sth = $dbh->prepare("INSERT INTO tsttbl (id, vc) values (?, ?)") - or die("Failed to prepare Insertion statement: ($DBI::err) $DBI::errstr\n"); -$retval = $sth->execute(2, 'two') - or die("2nd insertion failed: ($DBI::err) $DBI::errstr\n"); -die "2nd insertion inserted $retval rows instead of 1\n" unless $retval eq 1; - -# The disabled testa re due to known bug with driver. -# The misleading warnings withe "SQL-HY000" may be ignored. -$retval = $sth->execute(3, 'three'); - #or die("3rd insertion failed: ($DBI::err) $DBI::errstr\n"); -#die "3rd insertion inserted $retval rows instead of 1\n" unless $retval eq 1; -$retval = $sth->execute(4, 'four'); - #or die("4th insertion failed: ($DBI::err) $DBI::errstr\n"); -#die "4th insertion inserted $retval rows instead of 1\n" unless $retval eq 1; -$retval = $sth->execute(5, 'five'); - #or die("5th insertion failed: ($DBI::err) $DBI::errstr\n"); -#die "5th insertion inserted $retval rows instead of 1\n" unless $retval eq 1; -$dbh->commit; - # Some recent change to the HyperSQL server or to unixODBC has made this - # necessary, at least on UNIX. Some other transaction control command - # would probably be more appropriate here. - -# Now a simple/non-parameterized Query -$sth = $dbh->prepare("SELECT * FROM tsttbl WHERE id < 3") - or die("Failed to prepare SELECT statement: ($DBI::err) $DBI::errstr\n"); -$sth->execute() - or die("Execution of non-param. query failed : ($DBI::err) $DBI::errstr\n"); - -while ($row = $sth->fetch()) { - print(join '|', @$row); - print("\n"); -} -$sth->finish(); - -$dbh->do('rollback'); - -# Now a parameterized Query -$sth = $dbh->prepare("SELECT * FROM tsttbl WHERE id > ?") - or die("Failed to prepare SELECT statement: ($DBI::err) $DBI::errstr\n"); -# Use bind_param for variety -$sth->bind_param(1, 3); -$sth->execute() - or die("Exec. of parameterized query failed : ($DBI::err) $DBI::errstr\n"); - -while ($row = $sth->fetch()) { - print(join '|', @$row); - print("\n"); -} -$sth->finish(); - -$dbh->disconnect(); - -exit(0); diff --git a/database/hsqldb/sample/sample.py b/database/hsqldb/sample/sample.py deleted file mode 100644 index 9948a24c..00000000 --- a/database/hsqldb/sample/sample.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/python - -# $Id: sample.py 3633 2010-06-06 23:56:41Z unsaved $ - -# Sample Python script accessing HyperSQL through the Python pyodbc module. - -# This test HyperSQL client uses the ODBC DSN "tstdsn-a" to connect up to a -# HyperSQL server. Just configure your own DSN to use the HyperSQL ODBC -# driver, specifying the HyperSQL server host name, database name, user, -# password, etc. - -# N.b. there is some dependency or bug which requires pyodbc to use the -# ANSI variant of the HyperSQL ODBC Driver. Using the normal Unicode -# variant will generate the following error message when you try to connect: -# pyodbc.Error: ('0', '[0] [unixODBC]c (202) (SQLDriverConnectW)') -# It is quite possible that this issue will be taken care of when we fix a -# high-priority bug to do with switching between SQLDriverConnect and -# SQLDriverConnectW on UNIX. - -# Author: Blaine Simpson (blaine dot simpson at admc dot com) - -import pyodbc - -# Get a connection handle. -# In addition to the DSN name, you can override or supply additional DSN -# settings, such as "Uid" and "Pwd"; or define the DSN from scratch, starting -# with Driver. These settings are delimited with "; ". See pyodbc docs. -conn = pyodbc.connect("DSN=tstdsn-a") -try: - conn.autocommit = 0 - - cursor = conn.cursor(); - - cursor.execute("DROP TABLE tsttbl IF EXISTS"); - conn.commit(); # Some recent change to the HyperSQL server or to unixODBC - # has made this necessary, at least on UNIX. Some other - # transaction control command would probably be more - # appropriate here. - - cursor.execute( - "CREATE TABLE tsttbl(\n" - + " id BIGINT generated BY DEFAULT AS IDENTITY,\n" - + " vc VARCHAR(20),\n" - + " entrytime TIMESTAMP DEFAULT current_timestamp NOT NULL\n" - + ")"); - - # First a simple/non-parameterized Insertion - retval = cursor.execute("INSERT INTO tsttbl (id, vc) values (1, 'one')"); - if retval != 1: - raise Exception(('1st insertion inserted ' + repr(retval) - + ' rows instead of 1')) - # Now parameterized. Unfortunately, the Python DB API and pyodbc API do - # not allow re-use of a parsed statement. Cursor must be reparsed for - # each usage. - retval = cursor.execute("INSERT INTO tsttbl (id, vc) values (?, ?)", - 2, 'two'); - if retval != 1: - raise Exception(('2nd insertion inserted ' + repr(retval) - + ' rows instead of 2')) - retval = cursor.execute("INSERT INTO tsttbl (id, vc) values (?, ?)", - 3, 'three'); - if retval != 1: - raise Exception(('3rd insertion inserted ' + repr(retval) - + ' rows instead of 3')) - retval = cursor.execute("INSERT INTO tsttbl (id, vc) values (?, ?)", - 4, 'four'); - if retval != 1: - raise Exception(('4th insertion inserted ' + repr(retval) - + ' rows instead of 4')) - retval = cursor.execute("INSERT INTO tsttbl (id, vc) values (?, ?)", - 5, 'five'); - if retval != 1: - raise Exception(('5th insertion inserted ' + repr(retval) - + ' rows instead of 5')) - conn.commit(); - - # Non-parameterized query - for row in cursor.execute( - "SELECT * FROM tsttbl WHERE id < 3"): - print row - - # Non-parameterized query. As noted above, can't re-use parsed cursor. - for row in cursor.execute( - "SELECT * FROM tsttbl WHERE id > ?", 3): - # For variety, we format the files ourselves this time - print repr(row.ID) + '|' + row.VC + '|' + repr(row.ENTRYTIME) - -except Exception as e: - conn.rollback(); - raise e - -finally: - conn.close(); diff --git a/database/hsqldb/sample/sample.sql b/database/hsqldb/sample/sample.sql deleted file mode 100644 index 0f738e17..00000000 --- a/database/hsqldb/sample/sample.sql +++ /dev/null @@ -1,47 +0,0 @@ -/* - $Id: sample.sql 3605 2010-06-01 02:21:36Z unsaved $ - Exemplifies use of SqlTool. - PCTASK Table creation -*/ - -/* Ignore error for these two statements */ -\c true -DROP TABLE pctasklist; -DROP TABLE pctask; -\c false - -\p Creating table pctask -CREATE TABLE pctask ( - id integer identity, - name varchar(40), - description varchar(256), - url varchar(80), - UNIQUE (name) -); - -\p Creating table pctasklist -CREATE TABLE pctasklist ( - id integer identity, - host varchar(20) not null, - tasksequence int not null, - pctask integer, - assigndate timestamp default current_timestamp, - completedate timestamp, - show boolean default true, - FOREIGN KEY (pctask) REFERENCES pctask, - UNIQUE (host, tasksequence) -); - -\p Granting privileges -GRANT select ON pctask TO public; -GRANT all ON pctask TO tomcat; -GRANT select ON pctasklist TO public; -GRANT all ON pctasklist TO tomcat; - -\p Inserting test records -INSERT INTO pctask (name, description, url) VALUES ( - 'task one', 'Description for task 1', 'http://cnn.com'); -INSERT INTO pctasklist (host, tasksequence, pctask) VALUES ( - 'admc-masq', 101, (SELECT id FROM pctask WHERE name = 'task one')); - -commit; diff --git a/database/hsqldb/sample/sampledata.sql b/database/hsqldb/sample/sampledata.sql deleted file mode 100644 index 833d143f..00000000 --- a/database/hsqldb/sample/sampledata.sql +++ /dev/null @@ -1,822 +0,0 @@ -/* - * $Id: sampledata.sql 3348 2009-12-15 14:24:19Z unsaved $ - * - * Creates and populates database objects with sample data. - * This file was created by grabbing the commands made by creating - * sample data with the DatabaseManager utility. - */ - - -DROP TABLE Item IF EXISTS; -DROP TABLE Invoice IF EXISTS; -DROP TABLE Product IF EXISTS; -DROP TABLE Customer IF EXISTS; -CREATE TABLE Customer(ID INTEGER PRIMARY KEY,FirstName VARCHAR(20),LastName VARCHAR(30),Street VARCHAR(50),City VARCHAR(25)); -CREATE TABLE Product(ID INTEGER PRIMARY KEY,Name VARCHAR(30),Price DECIMAL); -CREATE TABLE Invoice(ID INTEGER PRIMARY KEY,CustomerID INTEGER,Total DECIMAL, FOREIGN KEY (CustomerId) REFERENCES Customer(ID) ON DELETE CASCADE); -CREATE TABLE Item(InvoiceID INTEGER,Item INTEGER,ProductID INTEGER,Quantity INTEGER,Cost DECIMAL,PRIMARY KEY(InvoiceID,Item), FOREIGN KEY (InvoiceId) REFERENCES Invoice (ID) ON DELETE CASCADE, FOREIGN KEY (ProductId) REFERENCES Product(ID) ON DELETE CASCADE); -INSERT INTO Customer VALUES(0,'Laura','Steel','429 Seventh Av.','Dallas'); -INSERT INTO Product VALUES(0,'Iron Iron',54); -INSERT INTO Customer VALUES(1,'Susanne','King','366 - 20th Ave.','Olten'); -INSERT INTO Product VALUES(1,'Chair Shoe',248); -INSERT INTO Customer VALUES(2,'Anne','Miller','20 Upland Pl.','Lyon'); -INSERT INTO Product VALUES(2,'Telephone Clock',248); -INSERT INTO Customer VALUES(3,'Michael','Clancy','542 Upland Pl.','San Francisco'); -INSERT INTO Product VALUES(3,'Chair Chair',254); -INSERT INTO Customer VALUES(4,'Sylvia','Ringer','365 College Av.','Dallas'); -INSERT INTO Product VALUES(4,'Ice Tea Shoe',128); -INSERT INTO Customer VALUES(5,'Laura','Miller','294 Seventh Av.','Paris'); -INSERT INTO Product VALUES(5,'Clock Clock',236); -INSERT INTO Customer VALUES(6,'Laura','White','506 Upland Pl.','Palo Alto'); -INSERT INTO Product VALUES(6,'Ice Tea Chair',98); -INSERT INTO Customer VALUES(7,'James','Peterson','231 Upland Pl.','San Francisco'); -INSERT INTO Product VALUES(7,'Telephone Shoe',84); -INSERT INTO Customer VALUES(8,'Andrew','Miller','288 - 20th Ave.','Seattle'); -INSERT INTO Product VALUES(8,'Ice Tea Clock',226); -INSERT INTO Customer VALUES(9,'James','Schneider','277 Seventh Av.','Berne'); -INSERT INTO Product VALUES(9,'Clock Telephone',172); -INSERT INTO Customer VALUES(10,'Anne','Fuller','135 Upland Pl.','Dallas'); -INSERT INTO Product VALUES(10,'Telephone Ice Tea',204); -INSERT INTO Customer VALUES(11,'Julia','White','412 Upland Pl.','Chicago'); -INSERT INTO Product VALUES(11,'Telephone Iron',88); -INSERT INTO Customer VALUES(12,'George','Ott','381 Upland Pl.','Palo Alto'); -INSERT INTO Product VALUES(12,'Clock Ice Tea',168); -INSERT INTO Customer VALUES(13,'Laura','Ringer','38 College Av.','New York'); -INSERT INTO Product VALUES(13,'Telephone Clock',180); -INSERT INTO Customer VALUES(14,'Bill','Karsen','53 College Av.','Oslo'); -INSERT INTO Product VALUES(14,'Telephone Iron',124); -INSERT INTO Customer VALUES(15,'Bill','Clancy','319 Upland Pl.','Seattle'); -INSERT INTO Product VALUES(15,'Ice Tea Chair',94); -INSERT INTO Customer VALUES(16,'John','Fuller','195 Seventh Av.','New York'); -INSERT INTO Product VALUES(16,'Ice Tea Shoe',194); -INSERT INTO Customer VALUES(17,'Laura','Ott','443 Seventh Av.','Lyon'); -INSERT INTO Product VALUES(17,'Clock Ice Tea',220); -INSERT INTO Customer VALUES(18,'Sylvia','Fuller','158 - 20th Ave.','Paris'); -INSERT INTO Product VALUES(18,'Chair Clock',172); -INSERT INTO Customer VALUES(19,'Susanne','Heiniger','86 - 20th Ave.','Dallas'); -INSERT INTO Product VALUES(19,'Ice Tea Ice Tea',110); -INSERT INTO Customer VALUES(20,'Janet','Schneider','309 - 20th Ave.','Oslo'); -INSERT INTO Product VALUES(20,'Ice Tea Telephone',200); -INSERT INTO Customer VALUES(21,'Julia','Clancy','18 Seventh Av.','Seattle'); -INSERT INTO Product VALUES(21,'Chair Chair',114); -INSERT INTO Customer VALUES(22,'Bill','Ott','250 - 20th Ave.','Berne'); -INSERT INTO Product VALUES(22,'Iron Iron',66); -INSERT INTO Customer VALUES(23,'Julia','Heiniger','358 College Av.','Boston'); -INSERT INTO Product VALUES(23,'Shoe Chair',76); -INSERT INTO Customer VALUES(24,'James','Sommer','333 Upland Pl.','Olten'); -INSERT INTO Product VALUES(24,'Chair Shoe',72); -INSERT INTO Customer VALUES(25,'Sylvia','Steel','269 College Av.','Paris'); -INSERT INTO Product VALUES(25,'Shoe Shoe',162); -INSERT INTO Customer VALUES(26,'James','Clancy','195 Upland Pl.','Oslo'); -INSERT INTO Product VALUES(26,'Shoe Shoe',252); -INSERT INTO Customer VALUES(27,'Bob','Sommer','509 College Av.','Seattle'); -INSERT INTO Product VALUES(27,'Telephone Iron',230); -INSERT INTO Customer VALUES(28,'Susanne','White','74 - 20th Ave.','Lyon'); -INSERT INTO Product VALUES(28,'Clock Iron',30); -INSERT INTO Customer VALUES(29,'Andrew','Smith','254 College Av.','New York'); -INSERT INTO Product VALUES(29,'Chair Telephone',112); -INSERT INTO Customer VALUES(30,'Bill','Sommer','362 - 20th Ave.','Olten'); -INSERT INTO Product VALUES(30,'Shoe Iron',232); -INSERT INTO Customer VALUES(31,'Bob','Ringer','371 College Av.','Olten'); -INSERT INTO Product VALUES(31,'Ice Tea Telephone',48); -INSERT INTO Customer VALUES(32,'Michael','Ott','339 College Av.','Boston'); -INSERT INTO Product VALUES(32,'Clock Iron',190); -INSERT INTO Customer VALUES(33,'Mary','King','491 College Av.','Oslo'); -INSERT INTO Product VALUES(33,'Iron Chair',182); -INSERT INTO Customer VALUES(34,'Julia','May','33 Upland Pl.','Seattle'); -INSERT INTO Product VALUES(34,'Chair Iron',256); -INSERT INTO Customer VALUES(35,'George','Karsen','412 College Av.','Chicago'); -INSERT INTO Product VALUES(35,'Telephone Shoe',76); -INSERT INTO Customer VALUES(36,'John','Steel','276 Upland Pl.','Dallas'); -INSERT INTO Product VALUES(36,'Ice Tea Iron',32); -INSERT INTO Customer VALUES(37,'Michael','Clancy','19 Seventh Av.','Dallas'); -INSERT INTO Product VALUES(37,'Clock Shoe',94); -INSERT INTO Customer VALUES(38,'Andrew','Heiniger','347 College Av.','Lyon'); -INSERT INTO Product VALUES(38,'Clock Ice Tea',216); -INSERT INTO Customer VALUES(39,'Mary','Karsen','202 College Av.','Chicago'); -INSERT INTO Product VALUES(39,'Ice Tea Shoe',154); -INSERT INTO Customer VALUES(40,'Susanne','Miller','440 - 20th Ave.','Dallas'); -INSERT INTO Product VALUES(40,'Shoe Clock',28); -INSERT INTO Customer VALUES(41,'Bill','King','546 College Av.','New York'); -INSERT INTO Product VALUES(41,'Clock Ice Tea',206); -INSERT INTO Customer VALUES(42,'Robert','Ott','503 Seventh Av.','Oslo'); -INSERT INTO Product VALUES(42,'Iron Chair',198); -INSERT INTO Customer VALUES(43,'Susanne','Smith','2 Upland Pl.','Dallas'); -INSERT INTO Product VALUES(43,'Telephone Clock',94); -INSERT INTO Customer VALUES(44,'Sylvia','Ott','361 College Av.','New York'); -INSERT INTO Product VALUES(44,'Ice Tea Ice Tea',96); -INSERT INTO Customer VALUES(45,'Janet','May','396 Seventh Av.','Oslo'); -INSERT INTO Product VALUES(45,'Iron Ice Tea',180); -INSERT INTO Customer VALUES(46,'Andrew','May','172 Seventh Av.','New York'); -INSERT INTO Product VALUES(46,'Ice Tea Clock',62); -INSERT INTO Customer VALUES(47,'Janet','Fuller','445 Upland Pl.','Dallas'); -INSERT INTO Product VALUES(47,'Ice Tea Iron',178); -INSERT INTO Customer VALUES(48,'Robert','White','549 Seventh Av.','San Francisco'); -INSERT INTO Product VALUES(48,'Clock Clock',210); -INSERT INTO Customer VALUES(49,'George','Fuller','534 - 20th Ave.','Olten'); -INSERT INTO Product VALUES(49,'Iron Iron',22); -INSERT INTO Invoice VALUES(0,0,0.0); -INSERT INTO Invoice VALUES(1,33,0.0); -INSERT INTO Invoice VALUES(2,23,0.0); -INSERT INTO Invoice VALUES(3,21,0.0); -INSERT INTO Invoice VALUES(4,30,0.0); -INSERT INTO Invoice VALUES(5,34,0.0); -INSERT INTO Invoice VALUES(6,19,0.0); -INSERT INTO Invoice VALUES(7,26,0.0); -INSERT INTO Invoice VALUES(8,29,0.0); -INSERT INTO Invoice VALUES(9,38,0.0); -INSERT INTO Invoice VALUES(10,24,0.0); -INSERT INTO Invoice VALUES(11,24,0.0); -INSERT INTO Invoice VALUES(12,23,0.0); -INSERT INTO Invoice VALUES(13,39,0.0); -INSERT INTO Invoice VALUES(14,35,0.0); -INSERT INTO Invoice VALUES(15,39,0.0); -INSERT INTO Invoice VALUES(16,45,0.0); -INSERT INTO Invoice VALUES(17,46,0.0); -INSERT INTO Invoice VALUES(18,4,0.0); -INSERT INTO Invoice VALUES(19,9,0.0); -INSERT INTO Invoice VALUES(20,19,0.0); -INSERT INTO Invoice VALUES(21,8,0.0); -INSERT INTO Invoice VALUES(22,40,0.0); -INSERT INTO Invoice VALUES(23,36,0.0); -INSERT INTO Invoice VALUES(24,15,0.0); -INSERT INTO Invoice VALUES(25,31,0.0); -INSERT INTO Invoice VALUES(26,27,0.0); -INSERT INTO Invoice VALUES(27,24,0.0); -INSERT INTO Invoice VALUES(28,35,0.0); -INSERT INTO Invoice VALUES(29,46,0.0); -INSERT INTO Invoice VALUES(30,13,0.0); -INSERT INTO Invoice VALUES(31,22,0.0); -INSERT INTO Invoice VALUES(32,20,0.0); -INSERT INTO Invoice VALUES(33,40,0.0); -INSERT INTO Invoice VALUES(34,33,0.0); -INSERT INTO Invoice VALUES(35,4,0.0); -INSERT INTO Invoice VALUES(36,42,0.0); -INSERT INTO Invoice VALUES(37,39,0.0); -INSERT INTO Invoice VALUES(38,46,0.0); -INSERT INTO Invoice VALUES(39,5,0.0); -INSERT INTO Invoice VALUES(40,4,0.0); -INSERT INTO Invoice VALUES(41,19,0.0); -INSERT INTO Invoice VALUES(42,38,0.0); -INSERT INTO Invoice VALUES(43,13,0.0); -INSERT INTO Invoice VALUES(44,32,0.0); -INSERT INTO Invoice VALUES(45,42,0.0); -INSERT INTO Invoice VALUES(46,24,0.0); -INSERT INTO Invoice VALUES(47,45,0.0); -INSERT INTO Invoice VALUES(48,22,0.0); -INSERT INTO Invoice VALUES(49,32,0.0); -INSERT INTO Item VALUES(0,12,1,11,1.5); -INSERT INTO Item VALUES(0,11,12,4,1.5); -INSERT INTO Item VALUES(0,10,4,8,1.5); -INSERT INTO Item VALUES(0,9,35,4,1.5); -INSERT INTO Item VALUES(0,8,0,23,1.5); -INSERT INTO Item VALUES(0,7,7,10,1.5); -INSERT INTO Item VALUES(0,6,16,9,1.5); -INSERT INTO Item VALUES(0,5,12,15,1.5); -INSERT INTO Item VALUES(0,4,47,1,1.5); -INSERT INTO Item VALUES(0,3,1,9,1.5); -INSERT INTO Item VALUES(0,2,47,3,1.5); -INSERT INTO Item VALUES(0,1,14,19,1.5); -INSERT INTO Item VALUES(0,0,7,12,1.5); -INSERT INTO Item VALUES(1,6,25,19,1.5); -INSERT INTO Item VALUES(1,5,25,9,1.5); -INSERT INTO Item VALUES(1,4,16,16,1.5); -INSERT INTO Item VALUES(1,3,38,8,1.5); -INSERT INTO Item VALUES(1,2,19,6,1.5); -INSERT INTO Item VALUES(1,1,0,9,1.5); -INSERT INTO Item VALUES(1,0,40,8,1.5); -INSERT INTO Item VALUES(2,16,36,24,1.5); -INSERT INTO Item VALUES(2,15,0,18,1.5); -INSERT INTO Item VALUES(2,14,48,19,1.5); -INSERT INTO Item VALUES(2,13,12,1,1.5); -INSERT INTO Item VALUES(2,12,21,15,1.5); -INSERT INTO Item VALUES(2,11,42,21,1.5); -INSERT INTO Item VALUES(2,10,49,11,1.5); -INSERT INTO Item VALUES(2,9,18,7,1.5); -INSERT INTO Item VALUES(2,8,39,2,1.5); -INSERT INTO Item VALUES(2,7,30,5,1.5); -INSERT INTO Item VALUES(2,6,43,8,1.5); -INSERT INTO Item VALUES(2,5,30,4,1.5); -INSERT INTO Item VALUES(2,4,38,18,1.5); -INSERT INTO Item VALUES(2,3,19,13,1.5); -INSERT INTO Item VALUES(2,2,11,9,1.5); -INSERT INTO Item VALUES(2,1,25,3,1.5); -INSERT INTO Item VALUES(2,0,4,18,1.5); -INSERT INTO Item VALUES(3,17,30,17,1.5); -INSERT INTO Item VALUES(3,16,19,11,1.5); -INSERT INTO Item VALUES(3,15,23,18,1.5); -INSERT INTO Item VALUES(3,14,17,22,1.5); -INSERT INTO Item VALUES(3,13,41,2,1.5); -INSERT INTO Item VALUES(3,12,41,22,1.5); -INSERT INTO Item VALUES(3,11,7,11,1.5); -INSERT INTO Item VALUES(3,10,10,17,1.5); -INSERT INTO Item VALUES(3,9,29,17,1.5); -INSERT INTO Item VALUES(3,8,49,9,1.5); -INSERT INTO Item VALUES(3,7,26,4,1.5); -INSERT INTO Item VALUES(3,6,13,18,1.5); -INSERT INTO Item VALUES(3,5,30,10,1.5); -INSERT INTO Item VALUES(3,4,20,12,1.5); -INSERT INTO Item VALUES(3,3,0,22,1.5); -INSERT INTO Item VALUES(3,2,49,3,1.5); -INSERT INTO Item VALUES(3,1,1,20,1.5); -INSERT INTO Item VALUES(3,0,11,21,1.5); -INSERT INTO Item VALUES(4,5,37,24,1.5); -INSERT INTO Item VALUES(4,4,9,18,1.5); -INSERT INTO Item VALUES(4,3,23,20,1.5); -INSERT INTO Item VALUES(4,2,41,23,1.5); -INSERT INTO Item VALUES(4,1,35,15,1.5); -INSERT INTO Item VALUES(4,0,28,9,1.5); -INSERT INTO Item VALUES(5,13,18,17,1.5); -INSERT INTO Item VALUES(5,12,8,15,1.5); -INSERT INTO Item VALUES(5,11,38,23,1.5); -INSERT INTO Item VALUES(5,10,28,18,1.5); -INSERT INTO Item VALUES(5,9,37,9,1.5); -INSERT INTO Item VALUES(5,8,20,3,1.5); -INSERT INTO Item VALUES(5,7,2,4,1.5); -INSERT INTO Item VALUES(5,6,7,9,1.5); -INSERT INTO Item VALUES(5,5,46,15,1.5); -INSERT INTO Item VALUES(5,4,32,14,1.5); -INSERT INTO Item VALUES(5,3,24,12,1.5); -INSERT INTO Item VALUES(5,2,20,18,1.5); -INSERT INTO Item VALUES(5,1,9,23,1.5); -INSERT INTO Item VALUES(5,0,9,5,1.5); -INSERT INTO Item VALUES(6,11,44,1,1.5); -INSERT INTO Item VALUES(6,10,16,13,1.5); -INSERT INTO Item VALUES(6,9,19,2,1.5); -INSERT INTO Item VALUES(6,8,41,19,1.5); -INSERT INTO Item VALUES(6,7,26,10,1.5); -INSERT INTO Item VALUES(6,6,37,22,1.5); -INSERT INTO Item VALUES(6,5,14,20,1.5); -INSERT INTO Item VALUES(6,4,31,20,1.5); -INSERT INTO Item VALUES(6,3,30,2,1.5); -INSERT INTO Item VALUES(6,2,23,8,1.5); -INSERT INTO Item VALUES(6,1,38,21,1.5); -INSERT INTO Item VALUES(6,0,15,20,1.5); -INSERT INTO Item VALUES(7,18,23,5,1.5); -INSERT INTO Item VALUES(7,17,40,1,1.5); -INSERT INTO Item VALUES(7,16,7,12,1.5); -INSERT INTO Item VALUES(7,15,24,17,1.5); -INSERT INTO Item VALUES(7,14,47,14,1.5); -INSERT INTO Item VALUES(7,13,32,23,1.5); -INSERT INTO Item VALUES(7,12,40,16,1.5); -INSERT INTO Item VALUES(7,11,19,13,1.5); -INSERT INTO Item VALUES(7,10,7,1,1.5); -INSERT INTO Item VALUES(7,9,9,21,1.5); -INSERT INTO Item VALUES(7,8,42,19,1.5); -INSERT INTO Item VALUES(7,7,2,22,1.5); -INSERT INTO Item VALUES(7,6,14,4,1.5); -INSERT INTO Item VALUES(7,5,24,10,1.5); -INSERT INTO Item VALUES(7,4,2,13,1.5); -INSERT INTO Item VALUES(7,3,30,2,1.5); -INSERT INTO Item VALUES(7,2,27,17,1.5); -INSERT INTO Item VALUES(7,1,23,12,1.5); -INSERT INTO Item VALUES(7,0,43,16,1.5); -INSERT INTO Item VALUES(8,9,21,23,1.5); -INSERT INTO Item VALUES(8,8,38,7,1.5); -INSERT INTO Item VALUES(8,7,6,5,1.5); -INSERT INTO Item VALUES(8,6,15,19,1.5); -INSERT INTO Item VALUES(8,5,24,18,1.5); -INSERT INTO Item VALUES(8,4,15,8,1.5); -INSERT INTO Item VALUES(8,3,41,16,1.5); -INSERT INTO Item VALUES(8,2,11,8,1.5); -INSERT INTO Item VALUES(8,1,44,16,1.5); -INSERT INTO Item VALUES(8,0,34,15,1.5); -INSERT INTO Item VALUES(9,19,48,23,1.5); -INSERT INTO Item VALUES(9,18,3,12,1.5); -INSERT INTO Item VALUES(9,17,13,17,1.5); -INSERT INTO Item VALUES(9,16,24,10,1.5); -INSERT INTO Item VALUES(9,15,48,23,1.5); -INSERT INTO Item VALUES(9,14,15,8,1.5); -INSERT INTO Item VALUES(9,13,42,13,1.5); -INSERT INTO Item VALUES(9,12,25,23,1.5); -INSERT INTO Item VALUES(9,11,12,16,1.5); -INSERT INTO Item VALUES(9,10,38,11,1.5); -INSERT INTO Item VALUES(9,9,13,6,1.5); -INSERT INTO Item VALUES(9,8,24,11,1.5); -INSERT INTO Item VALUES(9,7,2,22,1.5); -INSERT INTO Item VALUES(9,6,18,10,1.5); -INSERT INTO Item VALUES(9,5,6,2,1.5); -INSERT INTO Item VALUES(9,4,36,16,1.5); -INSERT INTO Item VALUES(9,3,4,14,1.5); -INSERT INTO Item VALUES(9,2,29,12,1.5); -INSERT INTO Item VALUES(9,1,18,21,1.5); -INSERT INTO Item VALUES(9,0,45,8,1.5); -INSERT INTO Item VALUES(10,9,5,10,1.5); -INSERT INTO Item VALUES(10,8,22,11,1.5); -INSERT INTO Item VALUES(10,7,4,13,1.5); -INSERT INTO Item VALUES(10,6,18,14,1.5); -INSERT INTO Item VALUES(10,5,5,24,1.5); -INSERT INTO Item VALUES(10,4,10,24,1.5); -INSERT INTO Item VALUES(10,3,46,1,1.5); -INSERT INTO Item VALUES(10,2,7,9,1.5); -INSERT INTO Item VALUES(10,1,33,17,1.5); -INSERT INTO Item VALUES(10,0,20,1,1.5); -INSERT INTO Item VALUES(11,8,20,1,1.5); -INSERT INTO Item VALUES(11,7,48,22,1.5); -INSERT INTO Item VALUES(11,6,0,12,1.5); -INSERT INTO Item VALUES(11,5,19,2,1.5); -INSERT INTO Item VALUES(11,4,47,16,1.5); -INSERT INTO Item VALUES(11,3,32,21,1.5); -INSERT INTO Item VALUES(11,2,0,3,1.5); -INSERT INTO Item VALUES(11,1,21,21,1.5); -INSERT INTO Item VALUES(11,0,45,10,1.5); -INSERT INTO Item VALUES(12,18,9,4,1.5); -INSERT INTO Item VALUES(12,17,31,15,1.5); -INSERT INTO Item VALUES(12,16,0,9,1.5); -INSERT INTO Item VALUES(12,15,22,16,1.5); -INSERT INTO Item VALUES(12,14,25,11,1.5); -INSERT INTO Item VALUES(12,13,36,21,1.5); -INSERT INTO Item VALUES(12,12,13,12,1.5); -INSERT INTO Item VALUES(12,11,28,16,1.5); -INSERT INTO Item VALUES(12,10,46,19,1.5); -INSERT INTO Item VALUES(12,9,25,22,1.5); -INSERT INTO Item VALUES(12,8,48,2,1.5); -INSERT INTO Item VALUES(12,7,48,7,1.5); -INSERT INTO Item VALUES(12,6,31,15,1.5); -INSERT INTO Item VALUES(12,5,37,17,1.5); -INSERT INTO Item VALUES(12,4,20,11,1.5); -INSERT INTO Item VALUES(12,3,0,18,1.5); -INSERT INTO Item VALUES(12,2,6,5,1.5); -INSERT INTO Item VALUES(12,1,41,19,1.5); -INSERT INTO Item VALUES(12,0,1,24,1.5); -INSERT INTO Item VALUES(13,21,40,1,1.5); -INSERT INTO Item VALUES(13,20,5,19,1.5); -INSERT INTO Item VALUES(13,19,42,18,1.5); -INSERT INTO Item VALUES(13,18,0,16,1.5); -INSERT INTO Item VALUES(13,17,32,18,1.5); -INSERT INTO Item VALUES(13,16,22,23,1.5); -INSERT INTO Item VALUES(13,15,0,20,1.5); -INSERT INTO Item VALUES(13,14,1,12,1.5); -INSERT INTO Item VALUES(13,13,10,20,1.5); -INSERT INTO Item VALUES(13,12,17,3,1.5); -INSERT INTO Item VALUES(13,11,14,3,1.5); -INSERT INTO Item VALUES(13,10,45,24,1.5); -INSERT INTO Item VALUES(13,9,24,10,1.5); -INSERT INTO Item VALUES(13,8,48,11,1.5); -INSERT INTO Item VALUES(13,7,29,24,1.5); -INSERT INTO Item VALUES(13,6,19,8,1.5); -INSERT INTO Item VALUES(13,5,22,19,1.5); -INSERT INTO Item VALUES(13,4,26,21,1.5); -INSERT INTO Item VALUES(13,3,32,2,1.5); -INSERT INTO Item VALUES(13,2,13,20,1.5); -INSERT INTO Item VALUES(13,1,1,1,1.5); -INSERT INTO Item VALUES(13,0,16,10,1.5); -INSERT INTO Item VALUES(14,13,11,23,1.5); -INSERT INTO Item VALUES(14,12,4,20,1.5); -INSERT INTO Item VALUES(14,11,25,15,1.5); -INSERT INTO Item VALUES(14,10,44,16,1.5); -INSERT INTO Item VALUES(14,9,13,16,1.5); -INSERT INTO Item VALUES(14,8,23,7,1.5); -INSERT INTO Item VALUES(14,7,43,4,1.5); -INSERT INTO Item VALUES(14,6,26,18,1.5); -INSERT INTO Item VALUES(14,5,11,8,1.5); -INSERT INTO Item VALUES(14,4,41,17,1.5); -INSERT INTO Item VALUES(14,3,34,11,1.5); -INSERT INTO Item VALUES(14,2,15,18,1.5); -INSERT INTO Item VALUES(14,1,9,22,1.5); -INSERT INTO Item VALUES(14,0,42,18,1.5); -INSERT INTO Item VALUES(15,2,24,6,1.5); -INSERT INTO Item VALUES(15,1,13,21,1.5); -INSERT INTO Item VALUES(15,0,17,12,1.5); -INSERT INTO Item VALUES(16,15,12,3,1.5); -INSERT INTO Item VALUES(16,14,0,19,1.5); -INSERT INTO Item VALUES(16,13,20,1,1.5); -INSERT INTO Item VALUES(16,12,18,2,1.5); -INSERT INTO Item VALUES(16,11,24,7,1.5); -INSERT INTO Item VALUES(16,10,43,8,1.5); -INSERT INTO Item VALUES(16,9,11,10,1.5); -INSERT INTO Item VALUES(16,8,13,17,1.5); -INSERT INTO Item VALUES(16,7,8,17,1.5); -INSERT INTO Item VALUES(16,6,44,7,1.5); -INSERT INTO Item VALUES(16,5,11,15,1.5); -INSERT INTO Item VALUES(16,4,10,24,1.5); -INSERT INTO Item VALUES(16,3,0,3,1.5); -INSERT INTO Item VALUES(16,2,20,15,1.5); -INSERT INTO Item VALUES(16,1,36,20,1.5); -INSERT INTO Item VALUES(16,0,18,15,1.5); -INSERT INTO Item VALUES(17,19,46,12,1.5); -INSERT INTO Item VALUES(17,18,5,9,1.5); -INSERT INTO Item VALUES(17,17,7,5,1.5); -INSERT INTO Item VALUES(17,16,8,16,1.5); -INSERT INTO Item VALUES(17,15,35,10,1.5); -INSERT INTO Item VALUES(17,14,18,2,1.5); -INSERT INTO Item VALUES(17,13,41,5,1.5); -INSERT INTO Item VALUES(17,12,22,16,1.5); -INSERT INTO Item VALUES(17,11,45,10,1.5); -INSERT INTO Item VALUES(17,10,10,12,1.5); -INSERT INTO Item VALUES(17,9,8,15,1.5); -INSERT INTO Item VALUES(17,8,49,8,1.5); -INSERT INTO Item VALUES(17,7,6,15,1.5); -INSERT INTO Item VALUES(17,6,43,6,1.5); -INSERT INTO Item VALUES(17,5,44,1,1.5); -INSERT INTO Item VALUES(17,4,23,2,1.5); -INSERT INTO Item VALUES(17,3,24,4,1.5); -INSERT INTO Item VALUES(17,2,44,11,1.5); -INSERT INTO Item VALUES(17,1,19,19,1.5); -INSERT INTO Item VALUES(17,0,16,8,1.5); -INSERT INTO Item VALUES(18,18,10,1,1.5); -INSERT INTO Item VALUES(18,17,8,1,1.5); -INSERT INTO Item VALUES(18,16,31,12,1.5); -INSERT INTO Item VALUES(18,15,44,20,1.5); -INSERT INTO Item VALUES(18,14,28,20,1.5); -INSERT INTO Item VALUES(18,13,14,12,1.5); -INSERT INTO Item VALUES(18,12,37,12,1.5); -INSERT INTO Item VALUES(18,11,30,8,1.5); -INSERT INTO Item VALUES(18,10,34,18,1.5); -INSERT INTO Item VALUES(18,9,2,2,1.5); -INSERT INTO Item VALUES(18,8,1,24,1.5); -INSERT INTO Item VALUES(18,7,15,14,1.5); -INSERT INTO Item VALUES(18,6,29,4,1.5); -INSERT INTO Item VALUES(18,5,15,6,1.5); -INSERT INTO Item VALUES(18,4,28,6,1.5); -INSERT INTO Item VALUES(18,3,19,8,1.5); -INSERT INTO Item VALUES(18,2,40,12,1.5); -INSERT INTO Item VALUES(18,1,33,12,1.5); -INSERT INTO Item VALUES(18,0,32,1,1.5); -INSERT INTO Item VALUES(19,4,36,24,1.5); -INSERT INTO Item VALUES(19,3,49,23,1.5); -INSERT INTO Item VALUES(19,2,4,22,1.5); -INSERT INTO Item VALUES(19,1,31,2,1.5); -INSERT INTO Item VALUES(19,0,12,7,1.5); -INSERT INTO Item VALUES(20,11,15,8,1.5); -INSERT INTO Item VALUES(20,10,25,11,1.5); -INSERT INTO Item VALUES(20,9,12,8,1.5); -INSERT INTO Item VALUES(20,8,44,18,1.5); -INSERT INTO Item VALUES(20,7,9,9,1.5); -INSERT INTO Item VALUES(20,6,20,2,1.5); -INSERT INTO Item VALUES(20,5,8,14,1.5); -INSERT INTO Item VALUES(20,4,30,13,1.5); -INSERT INTO Item VALUES(20,3,25,14,1.5); -INSERT INTO Item VALUES(20,2,24,22,1.5); -INSERT INTO Item VALUES(20,1,29,6,1.5); -INSERT INTO Item VALUES(20,0,47,15,1.5); -INSERT INTO Item VALUES(21,11,20,11,1.5); -INSERT INTO Item VALUES(21,10,19,14,1.5); -INSERT INTO Item VALUES(21,9,35,17,1.5); -INSERT INTO Item VALUES(21,8,44,19,1.5); -INSERT INTO Item VALUES(21,7,8,9,1.5); -INSERT INTO Item VALUES(21,6,26,7,1.5); -INSERT INTO Item VALUES(21,5,27,18,1.5); -INSERT INTO Item VALUES(21,4,49,22,1.5); -INSERT INTO Item VALUES(21,3,30,13,1.5); -INSERT INTO Item VALUES(21,2,31,17,1.5); -INSERT INTO Item VALUES(21,1,38,19,1.5); -INSERT INTO Item VALUES(21,0,9,10,1.5); -INSERT INTO Item VALUES(22,9,23,1,1.5); -INSERT INTO Item VALUES(22,8,3,2,1.5); -INSERT INTO Item VALUES(22,7,21,6,1.5); -INSERT INTO Item VALUES(22,6,4,11,1.5); -INSERT INTO Item VALUES(22,5,24,5,1.5); -INSERT INTO Item VALUES(22,4,5,21,1.5); -INSERT INTO Item VALUES(22,3,22,5,1.5); -INSERT INTO Item VALUES(22,2,12,20,1.5); -INSERT INTO Item VALUES(22,1,30,11,1.5); -INSERT INTO Item VALUES(22,0,9,6,1.5); -INSERT INTO Item VALUES(23,16,8,11,1.5); -INSERT INTO Item VALUES(23,15,13,17,1.5); -INSERT INTO Item VALUES(23,14,44,2,1.5); -INSERT INTO Item VALUES(23,13,14,17,1.5); -INSERT INTO Item VALUES(23,12,4,17,1.5); -INSERT INTO Item VALUES(23,11,41,8,1.5); -INSERT INTO Item VALUES(23,10,4,18,1.5); -INSERT INTO Item VALUES(23,9,20,18,1.5); -INSERT INTO Item VALUES(23,8,6,17,1.5); -INSERT INTO Item VALUES(23,7,39,3,1.5); -INSERT INTO Item VALUES(23,6,16,1,1.5); -INSERT INTO Item VALUES(23,5,32,14,1.5); -INSERT INTO Item VALUES(23,4,23,19,1.5); -INSERT INTO Item VALUES(23,3,40,19,1.5); -INSERT INTO Item VALUES(23,2,33,18,1.5); -INSERT INTO Item VALUES(23,1,26,8,1.5); -INSERT INTO Item VALUES(23,0,48,22,1.5); -INSERT INTO Item VALUES(24,15,39,17,1.5); -INSERT INTO Item VALUES(24,14,1,13,1.5); -INSERT INTO Item VALUES(24,13,15,21,1.5); -INSERT INTO Item VALUES(24,12,0,8,1.5); -INSERT INTO Item VALUES(24,11,1,4,1.5); -INSERT INTO Item VALUES(24,10,27,4,1.5); -INSERT INTO Item VALUES(24,9,21,8,1.5); -INSERT INTO Item VALUES(24,8,5,18,1.5); -INSERT INTO Item VALUES(24,7,7,13,1.5); -INSERT INTO Item VALUES(24,6,40,3,1.5); -INSERT INTO Item VALUES(24,5,35,16,1.5); -INSERT INTO Item VALUES(24,4,15,17,1.5); -INSERT INTO Item VALUES(24,3,17,23,1.5); -INSERT INTO Item VALUES(24,2,38,10,1.5); -INSERT INTO Item VALUES(24,1,46,18,1.5); -INSERT INTO Item VALUES(24,0,43,14,1.5); -INSERT INTO Item VALUES(25,8,38,3,1.5); -INSERT INTO Item VALUES(25,7,16,8,1.5); -INSERT INTO Item VALUES(25,6,21,18,1.5); -INSERT INTO Item VALUES(25,5,10,5,1.5); -INSERT INTO Item VALUES(25,4,47,10,1.5); -INSERT INTO Item VALUES(25,3,19,4,1.5); -INSERT INTO Item VALUES(25,2,13,8,1.5); -INSERT INTO Item VALUES(25,1,43,13,1.5); -INSERT INTO Item VALUES(25,0,5,15,1.5); -INSERT INTO Item VALUES(26,16,30,4,1.5); -INSERT INTO Item VALUES(26,15,8,6,1.5); -INSERT INTO Item VALUES(26,14,26,6,1.5); -INSERT INTO Item VALUES(26,13,13,10,1.5); -INSERT INTO Item VALUES(26,12,27,20,1.5); -INSERT INTO Item VALUES(26,11,18,3,1.5); -INSERT INTO Item VALUES(26,10,34,16,1.5); -INSERT INTO Item VALUES(26,9,1,23,1.5); -INSERT INTO Item VALUES(26,8,40,13,1.5); -INSERT INTO Item VALUES(26,7,4,16,1.5); -INSERT INTO Item VALUES(26,6,7,23,1.5); -INSERT INTO Item VALUES(26,5,38,4,1.5); -INSERT INTO Item VALUES(26,4,46,7,1.5); -INSERT INTO Item VALUES(26,3,16,3,1.5); -INSERT INTO Item VALUES(26,2,33,7,1.5); -INSERT INTO Item VALUES(26,1,43,21,1.5); -INSERT INTO Item VALUES(26,0,42,16,1.5); -INSERT INTO Item VALUES(27,2,19,1,1.5); -INSERT INTO Item VALUES(27,1,45,15,1.5); -INSERT INTO Item VALUES(27,0,24,15,1.5); -INSERT INTO Item VALUES(28,8,28,6,1.5); -INSERT INTO Item VALUES(28,7,28,8,1.5); -INSERT INTO Item VALUES(28,6,33,16,1.5); -INSERT INTO Item VALUES(28,5,49,4,1.5); -INSERT INTO Item VALUES(28,4,45,17,1.5); -INSERT INTO Item VALUES(28,3,6,3,1.5); -INSERT INTO Item VALUES(28,2,44,22,1.5); -INSERT INTO Item VALUES(28,1,15,13,1.5); -INSERT INTO Item VALUES(28,0,35,13,1.5); -INSERT INTO Item VALUES(29,8,35,6,1.5); -INSERT INTO Item VALUES(29,7,5,1,1.5); -INSERT INTO Item VALUES(29,6,4,16,1.5); -INSERT INTO Item VALUES(29,5,31,13,1.5); -INSERT INTO Item VALUES(29,4,4,7,1.5); -INSERT INTO Item VALUES(29,3,7,21,1.5); -INSERT INTO Item VALUES(29,2,17,23,1.5); -INSERT INTO Item VALUES(29,1,38,12,1.5); -INSERT INTO Item VALUES(29,0,33,17,1.5); -INSERT INTO Item VALUES(30,6,14,23,1.5); -INSERT INTO Item VALUES(30,5,43,23,1.5); -INSERT INTO Item VALUES(30,4,34,2,1.5); -INSERT INTO Item VALUES(30,3,33,2,1.5); -INSERT INTO Item VALUES(30,2,10,18,1.5); -INSERT INTO Item VALUES(30,1,16,19,1.5); -INSERT INTO Item VALUES(30,0,14,7,1.5); -INSERT INTO Item VALUES(31,10,0,3,1.5); -INSERT INTO Item VALUES(31,9,14,15,1.5); -INSERT INTO Item VALUES(31,8,7,5,1.5); -INSERT INTO Item VALUES(31,7,38,3,1.5); -INSERT INTO Item VALUES(31,6,26,16,1.5); -INSERT INTO Item VALUES(31,5,1,4,1.5); -INSERT INTO Item VALUES(31,4,8,14,1.5); -INSERT INTO Item VALUES(31,3,12,10,1.5); -INSERT INTO Item VALUES(31,2,4,3,1.5); -INSERT INTO Item VALUES(31,1,4,23,1.5); -INSERT INTO Item VALUES(31,0,33,10,1.5); -INSERT INTO Item VALUES(32,2,1,14,1.5); -INSERT INTO Item VALUES(32,1,30,13,1.5); -INSERT INTO Item VALUES(32,0,35,11,1.5); -INSERT INTO Item VALUES(33,15,38,7,1.5); -INSERT INTO Item VALUES(33,14,44,13,1.5); -INSERT INTO Item VALUES(33,13,25,16,1.5); -INSERT INTO Item VALUES(33,12,16,23,1.5); -INSERT INTO Item VALUES(33,11,5,7,1.5); -INSERT INTO Item VALUES(33,10,24,9,1.5); -INSERT INTO Item VALUES(33,9,29,5,1.5); -INSERT INTO Item VALUES(33,8,3,15,1.5); -INSERT INTO Item VALUES(33,7,43,10,1.5); -INSERT INTO Item VALUES(33,6,17,16,1.5); -INSERT INTO Item VALUES(33,5,8,11,1.5); -INSERT INTO Item VALUES(33,4,24,1,1.5); -INSERT INTO Item VALUES(33,3,48,1,1.5); -INSERT INTO Item VALUES(33,2,36,16,1.5); -INSERT INTO Item VALUES(33,1,10,21,1.5); -INSERT INTO Item VALUES(33,0,36,5,1.5); -INSERT INTO Item VALUES(34,14,46,7,1.5); -INSERT INTO Item VALUES(34,13,30,14,1.5); -INSERT INTO Item VALUES(34,12,43,21,1.5); -INSERT INTO Item VALUES(34,11,4,17,1.5); -INSERT INTO Item VALUES(34,10,41,16,1.5); -INSERT INTO Item VALUES(34,9,8,17,1.5); -INSERT INTO Item VALUES(34,8,3,1,1.5); -INSERT INTO Item VALUES(34,7,21,22,1.5); -INSERT INTO Item VALUES(34,6,32,7,1.5); -INSERT INTO Item VALUES(34,5,45,13,1.5); -INSERT INTO Item VALUES(34,4,27,1,1.5); -INSERT INTO Item VALUES(34,3,44,15,1.5); -INSERT INTO Item VALUES(34,2,28,22,1.5); -INSERT INTO Item VALUES(34,1,4,3,1.5); -INSERT INTO Item VALUES(34,0,10,22,1.5); -INSERT INTO Item VALUES(35,13,19,17,1.5); -INSERT INTO Item VALUES(35,12,7,23,1.5); -INSERT INTO Item VALUES(35,11,44,9,1.5); -INSERT INTO Item VALUES(35,10,17,11,1.5); -INSERT INTO Item VALUES(35,9,19,1,1.5); -INSERT INTO Item VALUES(35,8,0,1,1.5); -INSERT INTO Item VALUES(35,7,22,15,1.5); -INSERT INTO Item VALUES(35,6,5,4,1.5); -INSERT INTO Item VALUES(35,5,33,5,1.5); -INSERT INTO Item VALUES(35,4,14,17,1.5); -INSERT INTO Item VALUES(35,3,27,10,1.5); -INSERT INTO Item VALUES(35,2,14,4,1.5); -INSERT INTO Item VALUES(35,1,3,9,1.5); -INSERT INTO Item VALUES(35,0,20,17,1.5); -INSERT INTO Item VALUES(36,11,44,9,1.5); -INSERT INTO Item VALUES(36,10,47,11,1.5); -INSERT INTO Item VALUES(36,9,31,18,1.5); -INSERT INTO Item VALUES(36,8,4,21,1.5); -INSERT INTO Item VALUES(36,7,39,19,1.5); -INSERT INTO Item VALUES(36,6,39,20,1.5); -INSERT INTO Item VALUES(36,5,25,8,1.5); -INSERT INTO Item VALUES(36,4,40,5,1.5); -INSERT INTO Item VALUES(36,3,10,8,1.5); -INSERT INTO Item VALUES(36,2,1,6,1.5); -INSERT INTO Item VALUES(36,1,15,23,1.5); -INSERT INTO Item VALUES(36,0,18,13,1.5); -INSERT INTO Item VALUES(37,21,6,9,1.5); -INSERT INTO Item VALUES(37,20,14,1,1.5); -INSERT INTO Item VALUES(37,19,19,20,1.5); -INSERT INTO Item VALUES(37,18,26,22,1.5); -INSERT INTO Item VALUES(37,17,38,18,1.5); -INSERT INTO Item VALUES(37,16,27,8,1.5); -INSERT INTO Item VALUES(37,15,32,12,1.5); -INSERT INTO Item VALUES(37,14,12,3,1.5); -INSERT INTO Item VALUES(37,13,32,3,1.5); -INSERT INTO Item VALUES(37,12,24,23,1.5); -INSERT INTO Item VALUES(37,11,30,5,1.5); -INSERT INTO Item VALUES(37,10,1,18,1.5); -INSERT INTO Item VALUES(37,9,47,16,1.5); -INSERT INTO Item VALUES(37,8,46,9,1.5); -INSERT INTO Item VALUES(37,7,24,19,1.5); -INSERT INTO Item VALUES(37,6,34,12,1.5); -INSERT INTO Item VALUES(37,5,1,14,1.5); -INSERT INTO Item VALUES(37,4,13,20,1.5); -INSERT INTO Item VALUES(37,3,26,7,1.5); -INSERT INTO Item VALUES(37,2,36,8,1.5); -INSERT INTO Item VALUES(37,1,15,20,1.5); -INSERT INTO Item VALUES(37,0,41,24,1.5); -INSERT INTO Item VALUES(38,19,4,7,1.5); -INSERT INTO Item VALUES(38,18,28,20,1.5); -INSERT INTO Item VALUES(38,17,32,4,1.5); -INSERT INTO Item VALUES(38,16,40,18,1.5); -INSERT INTO Item VALUES(38,15,47,10,1.5); -INSERT INTO Item VALUES(38,14,20,7,1.5); -INSERT INTO Item VALUES(38,13,8,7,1.5); -INSERT INTO Item VALUES(38,12,1,18,1.5); -INSERT INTO Item VALUES(38,11,19,18,1.5); -INSERT INTO Item VALUES(38,10,4,18,1.5); -INSERT INTO Item VALUES(38,9,27,20,1.5); -INSERT INTO Item VALUES(38,8,40,10,1.5); -INSERT INTO Item VALUES(38,7,15,1,1.5); -INSERT INTO Item VALUES(38,6,5,19,1.5); -INSERT INTO Item VALUES(38,5,48,17,1.5); -INSERT INTO Item VALUES(38,4,45,14,1.5); -INSERT INTO Item VALUES(38,3,27,19,1.5); -INSERT INTO Item VALUES(38,2,4,8,1.5); -INSERT INTO Item VALUES(38,1,45,13,1.5); -INSERT INTO Item VALUES(38,0,48,14,1.5); -INSERT INTO Item VALUES(39,3,20,17,1.5); -INSERT INTO Item VALUES(39,2,39,16,1.5); -INSERT INTO Item VALUES(39,1,24,6,1.5); -INSERT INTO Item VALUES(39,0,10,12,1.5); -INSERT INTO Item VALUES(40,20,4,16,1.5); -INSERT INTO Item VALUES(40,19,7,23,1.5); -INSERT INTO Item VALUES(40,18,33,11,1.5); -INSERT INTO Item VALUES(40,17,4,20,1.5); -INSERT INTO Item VALUES(40,16,27,16,1.5); -INSERT INTO Item VALUES(40,15,22,12,1.5); -INSERT INTO Item VALUES(40,14,4,24,1.5); -INSERT INTO Item VALUES(40,13,6,8,1.5); -INSERT INTO Item VALUES(40,12,35,13,1.5); -INSERT INTO Item VALUES(40,11,27,2,1.5); -INSERT INTO Item VALUES(40,10,6,11,1.5); -INSERT INTO Item VALUES(40,9,40,17,1.5); -INSERT INTO Item VALUES(40,8,11,4,1.5); -INSERT INTO Item VALUES(40,7,31,1,1.5); -INSERT INTO Item VALUES(40,6,28,12,1.5); -INSERT INTO Item VALUES(40,5,32,18,1.5); -INSERT INTO Item VALUES(40,4,18,13,1.5); -INSERT INTO Item VALUES(40,3,26,10,1.5); -INSERT INTO Item VALUES(40,2,4,5,1.5); -INSERT INTO Item VALUES(40,1,45,24,1.5); -INSERT INTO Item VALUES(40,0,46,24,1.5); -INSERT INTO Item VALUES(41,11,48,15,1.5); -INSERT INTO Item VALUES(41,10,24,20,1.5); -INSERT INTO Item VALUES(41,9,26,21,1.5); -INSERT INTO Item VALUES(41,8,9,22,1.5); -INSERT INTO Item VALUES(41,7,22,18,1.5); -INSERT INTO Item VALUES(41,6,17,11,1.5); -INSERT INTO Item VALUES(41,5,9,21,1.5); -INSERT INTO Item VALUES(41,4,16,22,1.5); -INSERT INTO Item VALUES(41,3,29,20,1.5); -INSERT INTO Item VALUES(41,2,36,2,1.5); -INSERT INTO Item VALUES(41,1,47,19,1.5); -INSERT INTO Item VALUES(41,0,5,24,1.5); -INSERT INTO Item VALUES(42,4,48,15,1.5); -INSERT INTO Item VALUES(42,3,40,14,1.5); -INSERT INTO Item VALUES(42,2,40,19,1.5); -INSERT INTO Item VALUES(42,1,18,21,1.5); -INSERT INTO Item VALUES(42,0,48,9,1.5); -INSERT INTO Item VALUES(43,16,38,12,1.5); -INSERT INTO Item VALUES(43,15,48,7,1.5); -INSERT INTO Item VALUES(43,14,3,18,1.5); -INSERT INTO Item VALUES(43,13,44,22,1.5); -INSERT INTO Item VALUES(43,12,40,24,1.5); -INSERT INTO Item VALUES(43,11,49,23,1.5); -INSERT INTO Item VALUES(43,10,35,1,1.5); -INSERT INTO Item VALUES(43,9,7,23,1.5); -INSERT INTO Item VALUES(43,8,44,8,1.5); -INSERT INTO Item VALUES(43,7,11,15,1.5); -INSERT INTO Item VALUES(43,6,24,1,1.5); -INSERT INTO Item VALUES(43,5,33,6,1.5); -INSERT INTO Item VALUES(43,4,32,22,1.5); -INSERT INTO Item VALUES(43,3,6,18,1.5); -INSERT INTO Item VALUES(43,2,2,15,1.5); -INSERT INTO Item VALUES(43,1,18,19,1.5); -INSERT INTO Item VALUES(43,0,15,22,1.5); -INSERT INTO Item VALUES(44,8,28,23,1.5); -INSERT INTO Item VALUES(44,7,49,17,1.5); -INSERT INTO Item VALUES(44,6,14,15,1.5); -INSERT INTO Item VALUES(44,5,41,22,1.5); -INSERT INTO Item VALUES(44,4,12,3,1.5); -INSERT INTO Item VALUES(44,3,3,14,1.5); -INSERT INTO Item VALUES(44,2,17,14,1.5); -INSERT INTO Item VALUES(44,1,34,17,1.5); -INSERT INTO Item VALUES(44,0,33,20,1.5); -INSERT INTO Item VALUES(45,14,3,16,1.5); -INSERT INTO Item VALUES(45,13,47,8,1.5); -INSERT INTO Item VALUES(45,12,32,13,1.5); -INSERT INTO Item VALUES(45,11,31,22,1.5); -INSERT INTO Item VALUES(45,10,41,24,1.5); -INSERT INTO Item VALUES(45,9,26,18,1.5); -INSERT INTO Item VALUES(45,8,9,2,1.5); -INSERT INTO Item VALUES(45,7,6,24,1.5); -INSERT INTO Item VALUES(45,6,39,5,1.5); -INSERT INTO Item VALUES(45,5,45,17,1.5); -INSERT INTO Item VALUES(45,4,3,14,1.5); -INSERT INTO Item VALUES(45,3,14,11,1.5); -INSERT INTO Item VALUES(45,2,46,8,1.5); -INSERT INTO Item VALUES(45,1,11,6,1.5); -INSERT INTO Item VALUES(45,0,44,6,1.5); -INSERT INTO Item VALUES(46,17,12,23,1.5); -INSERT INTO Item VALUES(46,16,46,21,1.5); -INSERT INTO Item VALUES(46,15,40,11,1.5); -INSERT INTO Item VALUES(46,14,24,10,1.5); -INSERT INTO Item VALUES(46,13,36,20,1.5); -INSERT INTO Item VALUES(46,12,21,24,1.5); -INSERT INTO Item VALUES(46,11,1,4,1.5); -INSERT INTO Item VALUES(46,10,11,24,1.5); -INSERT INTO Item VALUES(46,9,7,4,1.5); -INSERT INTO Item VALUES(46,8,8,22,1.5); -INSERT INTO Item VALUES(46,7,49,9,1.5); -INSERT INTO Item VALUES(46,6,41,18,1.5); -INSERT INTO Item VALUES(46,5,25,9,1.5); -INSERT INTO Item VALUES(46,4,17,5,1.5); -INSERT INTO Item VALUES(46,3,21,19,1.5); -INSERT INTO Item VALUES(46,2,30,14,1.5); -INSERT INTO Item VALUES(46,1,12,24,1.5); -INSERT INTO Item VALUES(46,0,5,21,1.5); -INSERT INTO Item VALUES(47,13,33,8,1.5); -INSERT INTO Item VALUES(47,12,12,20,1.5); -INSERT INTO Item VALUES(47,11,35,10,1.5); -INSERT INTO Item VALUES(47,10,45,2,1.5); -INSERT INTO Item VALUES(47,9,32,9,1.5); -INSERT INTO Item VALUES(47,8,16,2,1.5); -INSERT INTO Item VALUES(47,7,28,14,1.5); -INSERT INTO Item VALUES(47,6,8,10,1.5); -INSERT INTO Item VALUES(47,5,40,8,1.5); -INSERT INTO Item VALUES(47,4,15,1,1.5); -INSERT INTO Item VALUES(47,3,1,4,1.5); -INSERT INTO Item VALUES(47,2,17,6,1.5); -INSERT INTO Item VALUES(47,1,23,13,1.5); -INSERT INTO Item VALUES(47,0,23,15,1.5); -INSERT INTO Item VALUES(48,10,41,10,1.5); -INSERT INTO Item VALUES(48,9,35,17,1.5); -INSERT INTO Item VALUES(48,8,5,12,1.5); -INSERT INTO Item VALUES(48,7,30,19,1.5); -INSERT INTO Item VALUES(48,6,11,17,1.5); -INSERT INTO Item VALUES(48,5,24,16,1.5); -INSERT INTO Item VALUES(48,4,48,4,1.5); -INSERT INTO Item VALUES(48,3,10,2,1.5); -INSERT INTO Item VALUES(48,2,23,10,1.5); -INSERT INTO Item VALUES(48,1,26,23,1.5); -INSERT INTO Item VALUES(48,0,6,23,1.5); -INSERT INTO Item VALUES(49,16,24,18,1.5); -INSERT INTO Item VALUES(49,15,19,24,1.5); -INSERT INTO Item VALUES(49,14,23,5,1.5); -INSERT INTO Item VALUES(49,13,6,22,1.5); -INSERT INTO Item VALUES(49,12,21,17,1.5); -INSERT INTO Item VALUES(49,11,40,15,1.5); -INSERT INTO Item VALUES(49,10,30,16,1.5); -INSERT INTO Item VALUES(49,9,7,24,1.5); -INSERT INTO Item VALUES(49,8,48,24,1.5); -INSERT INTO Item VALUES(49,7,6,21,1.5); -INSERT INTO Item VALUES(49,6,29,15,1.5); -INSERT INTO Item VALUES(49,5,16,1,1.5); -INSERT INTO Item VALUES(49,4,47,14,1.5); -INSERT INTO Item VALUES(49,3,17,19,1.5); -INSERT INTO Item VALUES(49,2,29,6,1.5); -INSERT INTO Item VALUES(49,1,22,16,1.5); -INSERT INTO Item VALUES(49,0,18,6,1.5); -UPDATE Product SET Price=ROUND(Price*.1,2); -UPDATE Item SET Cost=Cost*(SELECT Price FROM Product prod WHERE ProductID=prod.ID); -UPDATE Invoice SET Total=SELECT SUM(Cost*Quantity) FROM Item WHERE InvoiceID=Invoice.ID; - -COMMIT; diff --git a/database/hsqldb/sample/server.properties b/database/hsqldb/sample/server.properties deleted file mode 100644 index 8726b347..00000000 --- a/database/hsqldb/sample/server.properties +++ /dev/null @@ -1,20 +0,0 @@ -# Hsqldb Server cfg file. -# See the HyperSQL Network Listeners chapter of the HyperSQL User Guide. - -# Each server.database.X setting defines a database "catalog". -# I.e., an independent set of data. -# Each server.database.X setting corresponds exactly to the jdbc:hsqldb:* -# JDBC URL you would use if you wanted to get a direct (In-Process) -# Connection to the catalog instead of "serving" it. - -server.database.0=file:db0/db0 -# I suggest that, for every file: catalog you define, you add the -# connection property "ifexists=true" after the database instance -# is created (which happens simply by starting the Server one time). -# Just append ";ifexists=true" to the file: URL, like so: -# server.database.0=file:db0/db0;ifexists=true - -# server.dbname.0 defaults to "" (i.e. server.dbname.n for n==0), but -# the catalog definition n will be entirely ignored for n > 0 if you do not -# set server.dbname.n. I.e. dbname setting is required for n > 0, though it -# may be set to blank (e.g. "server.dbname.3=") diff --git a/database/hsqldb/sample/sqltool.rc b/database/hsqldb/sample/sqltool.rc deleted file mode 100644 index f5d2b521..00000000 --- a/database/hsqldb/sample/sqltool.rc +++ /dev/null @@ -1,234 +0,0 @@ -# $Id: sqltool.rc 6381 2021-11-18 21:45:56Z unsaved $ - -# This is a sample RC configuration file used by SqlTool, DatabaseManager, -# and any other program that uses the org.hsqldb.lib.RCData class. -# See the documentation for SqlTool for various ways to use this file. -# This is not a Java Properties file. It uses a custom format with stanzas, -# similar to .netrc files. - -# If you have the least concerns about security, then secure access to -# your RC file. - -# You can run SqlTool right now by copying this file to your home directory -# and running -# java -jar /path/to/sqltool.jar mem -# This will access the first urlid definition below in order to use a -# personal Memory-Only database. -# "url" values may, of course, contain JDBC connection properties, delimited -# with semicolons. -# As of revision 3347 of SqlFile, you can also connect to datasources defined -# here from within an SqlTool session/file with the command "\j urlid". - -# You can use Java system property values in this file like this: ${user.home} - -# Windows users are advised to use forward slashes instead of back-slashes, -# and to avoid paths containing spaces or other funny characters. (This -# recommendation applies to any Java app, not just SqlTool). - -# It is a runtime error to do a urlid lookup using RCData class and to not -# match any stanza (via urlid pattern) in this file. - -# Three features added recently. All are downward-compatible. -# 1. urlid field values in this file are now comma-separated (with optional -# whitespace before or after the commas) regular expressions. -# 2. Each individual urlid token value (per previous bullet) is a now a regular -# expression pattern that urlid lookups are compared to. N.b. patterns must -# match the entire lookup string, not just match "within" it. E.g. pattern -# of . would match lookup candidate "A" but not "AB". .+ will always match. -# 3. Though it is still an error to define the same exact urlid value more -# than once in this file, it is allowed (and useful) to have a url lookup -# match more than one urlid pattern and stanza. Assignments are applied -# sequentially, so you should generally add default settings with more -# liberal patterns, and override settings later in the file with more -# specific (or exact) patterns. - -# Since service discovery works great in all JREs for many years now, I -# have removed all 'driver' specifications here. JRE discover will -# automatically resolve the driver class based on the JDBC URL format. -# Most people use default ports, so I have removed port specification from -# examples except for Microsoft's Sql Server driver where you can't depend -# on a default port. -# In all cases, to specify a non-default port, insert colon and port number -# after the hostname or ip address in the JDBC URL, like -# jdbc:hsqldb:hsql://localhost:9977 or -# jdbc:sqlserver://hostname.admc.com:1433;databaseName=dbname - -# Amazon Aurora instances are access from JDBC exactly the same as the -# non-Aurora RDS counterpart. - -# For using any database engine other than HyperSQL, you must add the -# JDBC jar file and the SqlTool jar to your CLASSPATH then run a command like: -# java org.hsqldb.util.SqlTool... -# I.e., the "-jar" switch doesn't support modified classpath. -# (See SqlTool manual for how to do same thing using Java modules.) -# To oversimplify for non-developers, the two most common methods to set -# CLASSPATH for an executable tool like SqlTool are to either use the java -# "-cp" switch or set environmental variable CLASSPATH. -# Windows users can use graphical UI or CLI "set". Unix shell users must -# "export" in addition to assigning. -# -# All JDBC jar files used in these examples are available from Maven -# repositories. You can also get them from vendor web sites or with product -# bundles (especially database distributions). -# Most databases provide multiple variants. Most people will want a type 4 -# driver supporting your connection mechanism (most commonly TCP/IP service, -# but also database file access and others) and your client JRE version. -# By convention the variants are distinguished in segments of the jar file -# name before the final ".jar" . - - -# Global default. .+ matches all lookups: -urlid .+ -username SA -password - -# A personal Memory-Only (non-persistent) database. -# Inherits username and password from default setting above. -urlid mem -url jdbc:hsqldb:mem:memdbid - -# A personal, local, persistent database. -# Inherits username and password from default setting above. -urlid personal -url jdbc:hsqldb:file:${user.home}/db/personal;shutdown=true;ifexist=true -transiso TRANSACTION_READ_COMMITTED -# When connecting directly to a file database like this, you should -# use the shutdown connection property like this to shut down the DB -# properly when you exit the JVM. - -# This is for a hsqldb Server running with default settings on your local -# computer (and for which you have not changed the password for "SA"). -# Inherits username and password from default setting above. -# Default port 9001 -urlid localhost-sa -url jdbc:hsqldb:hsql://localhost - - - -# Template for a urlid for an Oracle database. -# Driver jar files from this century have format like "ojbc*.jar". -# Default port 1521 -urlid localhost-sa -# Avoid older drivers because they have quirks. -# You could use the thick driver instead of the thin, but I know of no reason -# why any Java app should. - -#urlid cardiff2 -# Can identify target database with either SID or global service name. -#url jdbc:oracle:thin:@//centos.admc.com/tstsid.admc -#username blaine -#password asecret - - -# Template for a TLS-encrypted HSQLDB Server. -# Remember that the hostname in hsqls (and https) JDBC URLs must match the -# CN of the server certificate (the port and instance alias that follows -# are not part of the certificate at all). -# You only need to set "truststore" if the server cert is not approved by -# your system default truststore (which a commercial certificate probably -# would be). -# Port defaults to 554. - -#urlid tls -#url jdbc:hsqldb:hsqls://db.admc.com:9001/lm2 -#username BLAINE -#password asecret -#truststore ${user.home}/ca/db/db-trust.store - - -# Template for a Postgresql database -# Driver jar files are of format like "postgresql-*.jar" -# Port defaults to 5432. -#urlid blainedb -#url jdbc:postgresql://idun.africawork.org/blainedb -#username blaine -#password asecret - -# Amazon RedShift (a fork of Postgresql) -# Driver jar files are of format like "redshift-jdbc*.jar" -# Port defaults to 5439. -#urlid redhshift -#url jdbc:redshift://clustername.hex.us-east-1.redshift.amazonaws.com/dev -#username awsuser -#password asecret - -# Template for a MySQL database. MySQL has poor JDBC support. -# The latest driver jar files are of format like "mysql-jdbc*.jar", but not -# long ago they were like "mysql-connector-java*.jar". -# Port defaults to 3306 -#urlid mysql-testdb -#url jdbc:mysql://hostname/dbname -#username root -#password asecret -# Alternatively, you can access MySQL using jdbc:mariadb URLs and driver. - -# Note that "databases" in SQL Server and Sybase are traditionally used for -# the same purpose as "schemas" with more SQL-compliant databases. - -# Template for a Microsoft SQL Server database using Microsoft's Driver -# Seems that some versions default to port 1433 and others to 1434. -# MSDN implies instances are port-specific, so can specify port or instname. -#urlid msprojsvr -# Driver jar files are of format like "mssql-jdbc-*.jar". -# Don't use older MS JDBC drivers (like SQL Server 2000 vintage) because they -# are pitifully incompetent, handling transactions incorrectly. -# I recommend that you do not use Microsoft's nonstandard format that -# includes backslashes. -#url jdbc:sqlserver://hostname;instanceName=instname;databaseName=dbname -# with port: -#url jdbc:sqlserver://hostname:1433;instanceName=instname;databaseName=dbname -#username myuser -#password asecret - -# Template for Microsoft SQL Server database using the JTDS Driver -# Looks like this project is no longer maintained, so you may be better off -# using the Microsoft driver above. -# http://jtds.sourceforge.net Jar file has name like "jtds-1.3.1.jar". -# Port defaults to 1433. -# MSDN implies instances are port-specific, so can specify port or instname. -#urlid nlyte -#username myuser -#password asecret -#url jdbc:jtds:sqlserver://myhost/nlyte;instance=MSSQLSERVER -# Where database is 'nlyte' and instance is 'MSSQLSERVER'. -# N.b. this is diff. from MS tools and JDBC driver where (depending on which -# document you read), instance or database X are specified like HOSTNAME\X. - -# Template for a Sybase database -#urlid sybase -#url jdbc:sybase:Tds:hostname:4100/dbname -#username blaine -#password asecret -# This is for the jConnect driver (requires jconn3.jar). - -# Derby / Java DB. -# Please see the Derby JDBC docs, because they have changed the organization -# of their driver jar files in recent years. Combining that with the different -# database types supported and jar file classpath chaining, and it's not -# feasible to document it adequately here. -# I'll just give one example using network service, which works with 10.15.2.0. -# Put files derbytools*.jar, derbyclient*.jar, derbyshared*.jar into a -# directory and include the path to the derbytools.jar in your classpath. -# Port defaults to 1527. -#url jdbc:derby://server:/databaseName -#username ${user.name} -#password any_noauthbydefault -# If you get the right classes into classpath, local file URLs are like: -#url jdbc:derby:path/to/derby/directory -# You can use \= to commit, since the Derby team decided (why???) -# not to implement the SQL standard statement "commit"!! -# Note that SqlTool can not shut down an embedded Derby database properly, -# since that requires an additional SQL connection just for that purpose. -# However, I've never lost data by shutting it down improperly. -# Other than not supporting this quirk of Derby, SqlTool is miles ahead of -# Derby's ij. - -# Maria DB -# With current versions, the MySQL driver does not work to access a Maria -# database (though the inverse works). -# Driver jar files are of format like "mariadb-java-client*.jar" -# Port defaults to 3306 -#urlid maria -#url jdbc:mariadb://hostname/db2 -#username blaine -#password asecret diff --git a/docs/src/08_concepts.adoc b/docs/src/08_concepts.adoc index 2aec4db4..65efb28b 100644 --- a/docs/src/08_concepts.adoc +++ b/docs/src/08_concepts.adoc @@ -33,6 +33,7 @@ class Question { class Category { - id: Long - name: String + - description: String - questions: Set + toString(): String + toJson(): JsonNode @@ -58,8 +59,16 @@ class GameSession { - createdAt: LocalDateTime - finishTime: LocalDateTime - score: int + - answeredQuestions: Set + - questionsToAnswer: List + - currentQuestion: Question + addQuestion(correct: boolean): void + + addAnsweredQuestion(question: Question): void + + isAnswered(question: Question): boolean + + getNextQuestion(): Question + toJson(): JsonNode + + hasQuestionId(idQuestion: Long): boolean + + getDuration(): String } class Role { @@ -90,316 +99,15 @@ class RestApiAccessLog { - details: String } -interface JsonEntity { - + toJson(): JsonNode -} - -interface PlayerService { - + addNewPlayer(dto: PlayerDto): Player - + getUsers(): List - + getUser(id: Long): Optional - + getUserByEmail(email: String): Optional - + getUserByUsername(username: String): Optional - + getUsersByRole(role: String): List - + generateapiKey(player: Player): void -} - -interface RoleService { - + addRole(role: RoleDto): Role - + getRole(name: String): Role - + getRoles(): List -} - -interface AnswerService { - + addNewAnswer(answer: Answer): void - + getAnswerPerQuestion(question: Question): List - + getAnswer(id: Long): Optional -} - -interface ApiKeyService { - + createApiKey(forPlayer: Player): ApiKey - + getApiKey(apiKey: String): ApiKey -} - -interface CategoryService { - + addNewCategory(category: Category): void - + getAllCategories(): List - + getCategory(id: Long): Optional - + getCategoryByName(geography: String): Category -} - -interface QuestionService { - + addNewQuestion(question: Question): void - + getAllQuestions(): List - + getQuestion(id: Long): Optional -} - -interface RestApiService { - + getPlayers(params: Map): List - + logAccess(apiKey: ApiKey, path: String, params: Map): void - + getQuestions(params: Map): List -} - -class CustomUserDetailsService { - - playerRepository: PlayerRepository - + loadUserByUsername(username: String): UserDetails - + mapRolesToAuthorities(roles: Collection): Collection< ? extends GrantedAuthority> -} - -class InsertSampleDataService { - - playerService: PlayerService - - questionService: QuestionService - - categoryService: CategoryService - - questionRepository: QuestionRepository - - gameSessionRepository: GameSessionRepository - + insertSampleQuestions(): void -} - -class PlayerServiceImpl { - - playerRepository: PlayerRepository - - roleService: RoleService - - passwordEncoder: PasswordEncoder - + addNewPlayer(dto: PlayerDto): Player - + getUsers(): List - + getUser(id: Long): Optional - + getUserByEmail(email: String): Optional - + getUserByUsername(username: String): Optional - + getUsersByRole(role: String): List - + generateApiKey(player: Player): void -} - -class RoleServiceImpl { - - roleRepository: RoleRepository - + addRole(role: RoleDto): Role - + getRole(name: String): Role - + getRoles(): List -} - -class AnswerServiceImpl { - - answerRepository: AnswerRepository - + addNewAnswer(answer: Answer): void - + getAnswersPerQuestion(question: Question): List - + getAnswer(id: Long): Optional -} - -class ApiKeyServiceImpl { - - apiKeyRepository: ApiKeyRepository - + createApiKey(forPlayer: Player): ApiKey - + getApiKey(apiKey: String): ApiKey -} - -class CategoryServiceImpl { - - categoryRepository: CategoryRepository - + addNewCategory(category: Category): void - + getAllCategories(): List - + getCategory(id: Long): Optional - + getCategoryByName(name: String): Category - + init(): void -} - -class QuestionServiceImpl { - - questionRepository: QuestionRepository - + addNewQuestion(question: Question): void - + getAllQuestions(): List - + getQuestion(id: Long): Optional -} - -class RestApiServiceImpl { - - playerService: PlayerService - - restApiLogRepository: RestApiLogRepository - - questionService: QuestionService - + getPlayers(params: Map): List - + logAccess(apiKey: ApiKey, path: String, params: Map): void - + getQuestions(params: Map): List -} - -class PlayerDto { - - username: String - - email: String - - password: String - - passwordConfirm: String - - roles: String[] -} - -class RoleDto { - - name: String -} - -class AbstractGeographyGenerator { - + getCategory(): Category -} - -class BorderQuestionGenerator { - - usedCountries: Set - + getAllBorderingCountries(resultsNode: JsonNode, correctCountry: String): List - + selectRandomIncorrectBorderingCountries(allBorderingCountries: List, correctCountry: String, count: int): List - + generateOptions(results: JsonNode, result: JsonNode): List - + generateCorrectAnswer(result: JsonNode): String - + getQuestionSubject(result: JsonNode): String - + getQuery(): String -} - -class CapitalQuestionGenerator { - + getQuery(): String - + getAllCapitals(resultsNode: JsonNode, correctCapital: String): List - + selectRandomIncorrectCapitals(allCapitals: List, correctCapital: String, count: int): List - + generateOptions(results: JsonNode, result: JsonNode): List - + generateCorrectAnswer(result: JsonNode): String - + getQuestionSubject(result: JsonNode): String -} - -class ContinentQuestionGeneration { - + getAllContinents(resultsNode: JsonNode, correctContinent: String): List - + selectRandomIncorrectContinents(allContinents: List, correctContinent: String, count: int): List - + generateOptions(results: JsonNode, result: JsonNode): List - + generateCorrectAnswer(result: JsonNode): String - + getQuestionSubject(result: JsonNode): String - + getQuery(): String -} - -class AbstractQuestionGenerator { - - questions: List - - categoryService: CategoryService - - query: String - - statement: String - + questionGenerator(statement: String, options: List, correctAnswer: String, category: Category): void - + getQuestions(): List - + generateOptions(results: JsonNode, result: JsonNode): List - + generateCorrectAnswer(result: JsonNode): String - + getQuestionSubject(result: JsonNode): String -} - -interface QuestionGenerator { - + getQuery(): String - + getQuestions(): List - + getCategory(): Category -} - -class QuestionGeneratorTestController { - + qgen: CapitalQuestionGenerator - + test(): void -} - -class SignUpValidator { - - playerService: PlayerService - + supports(clazz: Class): boolean - + validate(target: Object, errors: Errors): void -} - -JsonEntity <|.. Answer -JsonEntity <|.. Category -JsonEntity <|.. GameSession -JsonEntity <|.. Player -JsonEntity <|.. Question -AnswerService <|.. AnswerServiceImpl -ApiKeyService <|.. ApiKeyServiceImpl -CategoryService <|.. CategoryServiceImpl -PlayerService <|.. PlayerServiceImpl -QuestionService <|.. QuestionServiceImpl -RestApiService <|.. RestApiServiceImpl -RoleService <|.. RoleServiceImpl -AbstractGeographyGenerator --|> AbstractQuestionGenerator -BorderQuestionGenerator --|> AbstractGeographyGenerator -CapitalQuestionGenerator --|> AbstractGeographyGenerator -ContinentQuestionGeneration --|> AbstractGeographyGenerator -QuestionGenerator <|.. AbstractQuestionGenerator -RoleService ..> RoleDto -Role "*" - "*" Player -AnswerService ..> Answer -AnswerService ..> Question -ApiKeyService ..> Player -CategoryService ..> Category -PlayerService ..> PlayerDto -PlayerService ..> Player -QuestionService ..> Question -RestApiService ..> ApiKey -CustomUserDetailsService ..> Player -CustomUserDetailsService ..> Role -InsertSampleDataService "1" *- "1" PlayerService -InsertSampleDataService "1" *- "1" QuestionService -InsertSampleDataService "1" *- "1" CategoryService -InsertSampleDataService ..> PlayerDto -InsertSampleDataService ..> GameSession -InsertSampleDataService ..> QuestionGenerator -PlayerServiceImpl "1" *- "1" RoleService -PlayerServiceImpl "1" *- "1" PasswordEncoder -PlayerServiceImpl ..> Role -RestApiServiceImpl "1" *- "1" PlayerService -RestApiServiceImpl "1" *- "1" QuestionService -RestApiServiceImpl ..> Player -RestApiServiceImpl ..> Question -RestApiServiceImpl ..> Role -Answer "*" - "1" Question -ApiKey "1" - "1" Player -ApiKey "1" - "*" RestApiAccessLog -Category "1" - "*" Question -Player "1" - "*" GameSession -QuestionGeneratorTestController "1" *- "1" CapitalQuestionGenerator -QuestionGeneratorTestController ..> Question -AbstractQuestionGenerator "1" - "*" Question -AbstractQuestionGenerator "1" - "1" CategoryService -AbstractQuestionGenerator ..> Category -Validator <|.. SignUpValidator -SignUpValidator "1" - "1" PlayerService -SignUpValidator ..> PlayerDto - -@enduml ----- - -[plantuml, domain-model-2, svg] ----- -@startuml - -class AnswerDto { - - id: Long - - text: String - - correct: boolean -} - -class CategoryDto { - - id: Long - - name: String - - description: String - - questions: List -} - -class QuestionDto { - - id: Long - - statement: String - - options: List - - correctAnswer: AnswerDto - - category: CategoryDto -} - -class SecurityConfig { - - userDetailsService: UserDetailsService - - customAuthenticationFailureHandler: CustomAuthenticationFailureHandler - + passwordEncoder(): PasswordEncoder - + filterChain(http: HttpSecurity): SecurityFilterChain - + configureGlobal(auth: AuthenticationManagerBuilder): void - + isAuthenticated(): boolean -} - -class CustomAuthenticationFailureHandler { - + onAuthenticationFailure(request: HttpServletRequest, responde: HttpServletResponse, exception: AuthenticationException): void -} - -class CustomConfiguration { - + localeResolver(): LocaleResolver - + localeChangeInterceptor(): LocaleChangeInterceptor - + addInterceptors(registry: InterceptorRegistry): void -} - -class WiqEs04bApplication { - + main(args: String[]): void -} - -CategoryDto "1" - "*" QuestionDto -QuestionDto "1" *- "*" AnswerDto -SecurityConfig "1" *- "1" UserDetailsService -SecurityConfig "1" *- "1" CustomAuthenticationFailureHandler -CustomAuthenticationFailureHandler --|> SimpleUrlAuthenticationFailureHandler -WebMvcConfigurer <|.. CustomConfiguration +Role "*" -- "*" Player +Answer "4 " --* "1" Question : Options +Answer "1 " -- " 1" Question : Correct Answer +ApiKey "1" --* "1" Player +ApiKey "1" *-- "*" RestApiAccessLog +Category "1" -- "*" Question +Player "1" *-- "*" GameSession +GameSession "1" -- "*" Question : Answered Questions +GameSession "1" -- "*" Question : Questions To Answer @enduml ---- diff --git a/docs/src/09_architecture_decisions.adoc b/docs/src/09_architecture_decisions.adoc index 8d42e6df..fcfeb49c 100644 --- a/docs/src/09_architecture_decisions.adoc +++ b/docs/src/09_architecture_decisions.adoc @@ -6,4 +6,11 @@ ifndef::imagesdir[:imagesdir: ../images] The purpose of this section is to create an ordered list of architectural decisions that we will make as we develop the project. This list will be ordered according to the importance of the decision. * https://github.com/Arquisoft/wiq_es04b/wiki/Record-of-architectural-decisions#protection-of-the-master-branch[ADR 01] - Protection of the master branch -* https://github.com/Arquisoft/wiq_es04b/wiki/Record-of-architectural-decisions#switch-from-javascript-to-java-with-springboot[ADR 02] - Switch from JavaScript to Java with Spring \ No newline at end of file +* https://github.com/Arquisoft/wiq_es04b/wiki/Record-of-architectural-decisions#switch-from-javascript-to-java-with-springboot[ADR 02] - Switch from JavaScript to Java with Spring +* https://github.com/Arquisoft/wiq_es04b/wiki/Record-of-architectural-decisions#mvc-pattern[ADR 03] - MVC Pattern +* https://github.com/Arquisoft/wiq_es04b/wiki/Record-of-architectural-decisions#hexagonal-architecture[ADR 04] - Hexagonal architecture +* https://github.com/Arquisoft/wiq_es04b/wiki/Record-of-architectural-decisions#dto-pattern[ADR 05] - DTO Pattern +* https://github.com/Arquisoft/wiq_es04b/wiki/Record-of-architectural-decisions#mysql-in-production-and-hsqldb-in-local[ADR 06] - MySQL in production and HSQLDB in local +* https://github.com/Arquisoft/wiq_es04b/wiki/Record-of-architectural-decisions#monolithic-architecture[ADR 07] - Monolithic architecture +* https://github.com/Arquisoft/wiq_es04b/wiki/Record-of-architectural-decisions#use-of-tbd[ADR 08] - Use of TBD +* https://github.com/Arquisoft/wiq_es04b/wiki/Record-of-architectural-decisions#questions-refreshing[ADR 09] - Questions refreshing \ No newline at end of file diff --git a/docs/src/11_technical_risks.adoc b/docs/src/11_technical_risks.adoc index e1cfdd1b..32043b2f 100644 --- a/docs/src/11_technical_risks.adoc +++ b/docs/src/11_technical_risks.adoc @@ -19,4 +19,4 @@ ifndef::imagesdir[:imagesdir: ../images] | Priority | Debt | Description | Low | Microservices | Research about microservices and what they can contribute to the project -|== +|=== diff --git a/docs/src/12_glossary.adoc b/docs/src/12_glossary.adoc index bce68d0f..5ba9eab8 100644 --- a/docs/src/12_glossary.adoc +++ b/docs/src/12_glossary.adoc @@ -23,4 +23,5 @@ ifndef::imagesdir[:imagesdir: ../images] |RestApiAccessLog | This entity is used to register the access to the application. |Associations | Represents the associations between entities. It has internal classes for each association. + |=== diff --git a/pom.xml b/pom.xml index 86487ac8..7961a9d5 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,8 @@ wiq_es04b 17 + src/main/java,src/test/resources/features + ${project.basedir}/target/jacoco.exec @@ -29,11 +31,6 @@ org.springframework.boot spring-boot-starter-web - - org.springframework.boot - spring-boot-starter-test - test - org.projectlombok lombok @@ -72,16 +69,159 @@ commons-validator 1.7 - + + org.seleniumhq.selenium + selenium-java + 4.1.0 + + + + io.github.bonigarcia + webdrivermanager + 5.0.3 + + + org.apache.httpcomponents.client5 + httpclient5 + 5.1 + + + io.cucumber + cucumber-java + 7.14.0 + test + + + io.cucumber + cucumber-junit + 7.14.0 + test + + + io.cucumber + cucumber-spring + 7.14.0 + test + + + io.cucumber + cucumber-junit-platform-engine + 7.14.0 + test + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.5.0 + + + org.jacoco + jacoco-maven-plugin + 0.8.11 + + + + prepare-agent + + + + report + report + + report + + + + XML + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + + **/CucumberRunnerTests.java + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.0.0-M5 + + + + verify + + + + + + **/CucumberRunnerTests.java + + + org.springframework.boot spring-boot-maven-plugin + + + -javaagent:${settings.localRepository}/org/jacoco/org.jacoco.agent/0.8.11/org.jacoco.agent-0.8.11-runtime.jar=destfile=${project.build.directory}/jacoco.exec,includes=*,output=file + + + + + + exclude-junit + + + env.EXCLUDE_JUNIT + true + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.jupiter + junit-jupiter-engine + + + + + - + + + include-junit + + true + + !env.EXCLUDE_JUNIT + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + \ No newline at end of file diff --git a/src/main/java/com/uniovi/WiqEs04bApplication.java b/src/main/java/com/uniovi/WiqEs04bApplication.java index 7cd90279..5bfb46bc 100644 --- a/src/main/java/com/uniovi/WiqEs04bApplication.java +++ b/src/main/java/com/uniovi/WiqEs04bApplication.java @@ -1,12 +1,7 @@ package com.uniovi; -import jakarta.persistence.Persistence; import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @SpringBootApplication public class WiqEs04bApplication { diff --git a/src/main/java/com/uniovi/components/MultipleQuestionGenerator.java b/src/main/java/com/uniovi/components/MultipleQuestionGenerator.java index d8409cc5..e5001403 100644 --- a/src/main/java/com/uniovi/components/MultipleQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/MultipleQuestionGenerator.java @@ -1,9 +1,9 @@ package com.uniovi.components; import com.uniovi.components.generators.QuestionGenerator; -import com.uniovi.entities.Category; import com.uniovi.entities.Question; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -14,7 +14,7 @@ public MultipleQuestionGenerator(QuestionGenerator... generators) { this.generators = generators; } - public List getQuestions() { + public List getQuestions() throws InterruptedException, IOException { List questions = new ArrayList<>(); for (QuestionGenerator generator : generators) { questions.addAll(generator.getQuestions()); diff --git a/src/main/java/com/uniovi/components/QuestionGeneratorTestController.java b/src/main/java/com/uniovi/components/QuestionGeneratorTestController.java index bb954701..89a28e69 100644 --- a/src/main/java/com/uniovi/components/QuestionGeneratorTestController.java +++ b/src/main/java/com/uniovi/components/QuestionGeneratorTestController.java @@ -1,13 +1,7 @@ package com.uniovi.components; -import com.uniovi.components.generators.geography.CapitalQuestionGenerator; -import com.uniovi.entities.Question; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - @RestController public class QuestionGeneratorTestController { diff --git a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java index 81006a95..9754c2c5 100644 --- a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java @@ -6,23 +6,25 @@ import com.uniovi.entities.Category; import com.uniovi.entities.Question; import com.uniovi.services.CategoryService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; -import org.springframework.stereotype.Component; +import java.io.IOException; import java.net.URI; import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; +import java.util.Random; public abstract class AbstractQuestionGenerator implements QuestionGenerator{ private List questions = new ArrayList<>(); protected final CategoryService categoryService; - private String query; + + protected Random random = new SecureRandom(); + protected String statement; protected String language; @@ -46,12 +48,10 @@ public void questionGenerator(String statement, List options, String cor questions.add(question); } - public List getQuestions() { + public List getQuestions() throws InterruptedException, IOException { HttpClient client = HttpClient.newHttpClient(); - try { - String endpointUrl = "https://query.wikidata.org/sparql?query=" + - URLEncoder.encode(this.getQuery(), StandardCharsets.UTF_8.toString()) + + URLEncoder.encode(this.getQuery(), StandardCharsets.UTF_8) + "&format=json"; HttpRequest request = HttpRequest.newBuilder() @@ -72,14 +72,10 @@ public List getQuestions() { List options = this.generateOptions(resultsNode, result); String correctAnswer = this.generateCorrectAnswer(result); - String statement = this.getQuestionSubject(result); - questionGenerator(statement, options, correctAnswer, this.getCategory()); + String questionStatement = this.getQuestionSubject(result); + questionGenerator(questionStatement, options, correctAnswer, this.getCategory()); } - } catch (Exception e) { - throw new RuntimeException(e); - } - return questions; } @@ -87,4 +83,5 @@ public List getQuestions() { protected abstract String generateCorrectAnswer(JsonNode result); protected abstract String getQuestionSubject(JsonNode result); + } diff --git a/src/main/java/com/uniovi/components/generators/QuestionGenerator.java b/src/main/java/com/uniovi/components/generators/QuestionGenerator.java index ccaa4dab..fd9356fa 100644 --- a/src/main/java/com/uniovi/components/generators/QuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/QuestionGenerator.java @@ -4,13 +4,14 @@ import com.uniovi.entities.Question; import org.springframework.stereotype.Component; +import java.io.IOException; import java.util.List; @Component public interface QuestionGenerator { String getQuery(); - List getQuestions(); + List getQuestions() throws InterruptedException, IOException; Category getCategory(); diff --git a/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java index f791f1e5..539b1c13 100644 --- a/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java @@ -6,16 +6,18 @@ import java.util.*; public class BorderQuestionGenerator extends AbstractGeographyGenerator{ - private static final Map STATEMENTS = new HashMap<>() { - { - put("en", "Which countries share a border with "); - put("es", "¿Con qué países comparte frontera "); - } - }; + private static Map STATEMENTS = null; private Set usedCountries = new HashSet<>(); public BorderQuestionGenerator(CategoryService categoryService, String language) { super(categoryService); + if (STATEMENTS == null) { + STATEMENTS = new HashMap<>(); + STATEMENTS.put("en", "Which countries share a border with "); + STATEMENTS.put("es", "¿Con qué países comparte frontera "); + STATEMENTS.put("fr", "Avec quels pays partage-t-il une frontière "); + } + this.statement = STATEMENTS.get(language); this.language = language; } @@ -33,7 +35,6 @@ private List getAllBorderingCountries(JsonNode resultsNode, String corre private List selectRandomIncorrectBorderingCountries(List allBorderingCountries, String correctCountry, int count) { List incorrectBorderingCountries = new ArrayList<>(); - Random random = new Random(); while (incorrectBorderingCountries.size() < count && allBorderingCountries.size() > 0) { int randomIndex = random.nextInt(allBorderingCountries.size()); String selectedBorderingCountry = allBorderingCountries.remove(randomIndex); diff --git a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java index e5d91727..924ef3cf 100644 --- a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java @@ -8,15 +8,17 @@ import java.util.*; public class CapitalQuestionGenerator extends AbstractGeographyGenerator{ - private static final Map STATEMENTS = new HashMap<>() { - { - put("en", "What is the capital of "); - put("es", "¿Cuál es la capital de "); - } - }; + private static Map STATEMENTS = null; public CapitalQuestionGenerator(CategoryService categoryService, String language) { super(categoryService); + if (STATEMENTS == null) { + STATEMENTS = new HashMap<>(); + STATEMENTS.put("en", "What is the capital of "); + STATEMENTS.put("es", "¿Cuál es la capital de "); + STATEMENTS.put("fr", "Quelle est la capitale de "); + } + this.statement = STATEMENTS.get(language); this.language = language; } @@ -48,7 +50,6 @@ private List getAllCapitals(JsonNode resultsNode, String correctCapital) private List selectRandomIncorrectCapitals(List allCapitals, String correctCapital, int count) { List incorrectCapitals = new ArrayList<>(); - Random random = new Random(); while (incorrectCapitals.size() < count && allCapitals.size() > 0) { int randomIndex = random.nextInt(allCapitals.size()); String selectedCapital = allCapitals.remove(randomIndex); diff --git a/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java b/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java index b1d476ae..df48ec41 100644 --- a/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java +++ b/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java @@ -7,15 +7,18 @@ import java.util.*; public class ContinentQuestionGeneration extends AbstractGeographyGenerator{ - private static final Map STATEMENTS = new HashMap<>() { - { - put("en", "In which continent is "); - put("es", "¿En qué continente se encuentra "); - } - }; + private static Map STATEMENTS = null; public ContinentQuestionGeneration(CategoryService categoryService, String language) { super(categoryService); + + if (STATEMENTS == null) { + STATEMENTS = new HashMap<>(); + STATEMENTS.put("en", "In which continent is "); + STATEMENTS.put("es", "¿En qué continente se encuentra "); + STATEMENTS.put("fr", "Sur quel continent est-il situé "); + } + this.statement = STATEMENTS.get(language); this.language = language; } @@ -34,7 +37,6 @@ private List getAllContinents(JsonNode resultsNode, String correctContin private List selectRandomIncorrectContinents(List allContinents, String correctContinent, int count) { List incorrectContinents = new ArrayList<>(); - Random random = new Random(); while (incorrectContinents.size() < count && allContinents.size() > 0) { int randomIndex = random.nextInt(allContinents.size()); String selectedCapital = allContinents.remove(randomIndex); diff --git a/src/main/java/com/uniovi/configuration/CustomConfiguration.java b/src/main/java/com/uniovi/configuration/CustomConfiguration.java index dbb9eb11..5981122e 100644 --- a/src/main/java/com/uniovi/configuration/CustomConfiguration.java +++ b/src/main/java/com/uniovi/configuration/CustomConfiguration.java @@ -1,14 +1,11 @@ package com.uniovi.configuration; -import jakarta.persistence.EntityManagerFactory; -import org.hibernate.SessionFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.PageRequest; import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; diff --git a/src/main/java/com/uniovi/configuration/SecurityConfig.java b/src/main/java/com/uniovi/configuration/SecurityConfig.java index 0a6a2ec5..c0af5d20 100644 --- a/src/main/java/com/uniovi/configuration/SecurityConfig.java +++ b/src/main/java/com/uniovi/configuration/SecurityConfig.java @@ -1,6 +1,5 @@ package com.uniovi.configuration; -import jakarta.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -38,6 +37,9 @@ public static PasswordEncoder passwordEncoder(){ @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http + .csrf(csrf -> csrf + .ignoringRequestMatchers("/api/**") + ) .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/css/**", "/img/**", "/script/**").permitAll() diff --git a/src/main/java/com/uniovi/controllers/GameController.java b/src/main/java/com/uniovi/controllers/GameController.java index beed332c..59c20083 100644 --- a/src/main/java/com/uniovi/controllers/GameController.java +++ b/src/main/java/com/uniovi/controllers/GameController.java @@ -16,6 +16,7 @@ import java.security.Principal; import java.time.Duration; import java.time.LocalDateTime; +import java.util.Optional; @Controller public class GameController { @@ -80,13 +81,13 @@ public String getCheckResult(@PathVariable Long idQuestion, @PathVariable Long i || getRemainingTime(gameSession) <= 0) { model.addAttribute("correctAnswer", gameSession.getCurrentQuestion().getCorrectAnswer()); model.addAttribute("messageKey", "timeRunOut.result"); - model.addAttribute("logoImage", "/images/logo_incorrect.png"); + model.addAttribute("logoImage", "/images/logo_incorrect.svg"); gameSession.addAnsweredQuestion(gameSession.getCurrentQuestion()); gameSession.addQuestion(false, 0); } else if(questionService.checkAnswer(idQuestion, idAnswer)) { model.addAttribute("messageKey", "correctAnswer.result"); - model.addAttribute("logoImage", "/images/logo_correct.png"); + model.addAttribute("logoImage", "/images/logo_correct.svg"); if (!gameSession.isAnswered(gameSession.getCurrentQuestion())) { gameSession.addQuestion(true, getRemainingTime(gameSession)); @@ -96,7 +97,7 @@ else if(questionService.checkAnswer(idQuestion, idAnswer)) { } else { model.addAttribute("correctAnswer", gameSession.getCurrentQuestion().getCorrectAnswer()); model.addAttribute("messageKey", "failedAnswer.result"); - model.addAttribute("logoImage", "/images/logo_incorrect.png"); + model.addAttribute("logoImage", "/images/logo_incorrect.svg"); gameSession.addAnsweredQuestion(gameSession.getCurrentQuestion()); gameSession.addQuestion(false, 0); } @@ -148,8 +149,19 @@ public String getPoints(HttpSession session) { return "0"; } + @GetMapping("/game/currentQuestion") + @ResponseBody + public String getCurrentQuestion(HttpSession session) { + GameSession gameSession = (GameSession) session.getAttribute("gameSession"); + if (gameSession != null) + return String.valueOf(gameSession.getAnsweredQuestions().size()+1); + else + return "0"; + } + private Player getLoggedInPlayer(Principal principal) { - return playerService.getUserByUsername(principal.getName()).get(); + Optional player = playerService.getUserByUsername(principal.getName()); + return player.orElse(null); } /** diff --git a/src/main/java/com/uniovi/controllers/HomeController.java b/src/main/java/com/uniovi/controllers/HomeController.java index 5ae72609..a89f0f31 100644 --- a/src/main/java/com/uniovi/controllers/HomeController.java +++ b/src/main/java/com/uniovi/controllers/HomeController.java @@ -1,18 +1,13 @@ package com.uniovi.controllers; -import com.uniovi.entities.ApiKey; import com.uniovi.entities.Player; import com.uniovi.services.ApiKeyService; import com.uniovi.services.PlayerService; -import com.uniovi.services.QuestionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; - -import java.util.Random; @Controller public class HomeController{ @@ -30,11 +25,6 @@ public String home(){ return "index"; } - @GetMapping("/api") - public String apiHome() { - return "api/apiHome"; - } - @GetMapping("/home/apikey") public String apiKeyHome(Authentication auth, Model model) { Player player = playerService.getUserByUsername(auth.getName()).get(); diff --git a/src/main/java/com/uniovi/controllers/PlayersController.java b/src/main/java/com/uniovi/controllers/PlayersController.java index 1f63f8ed..27bb9564 100644 --- a/src/main/java/com/uniovi/controllers/PlayersController.java +++ b/src/main/java/com/uniovi/controllers/PlayersController.java @@ -23,6 +23,7 @@ import org.springframework.web.bind.annotation.RequestParam; import java.security.Principal; +import java.util.Optional; @Controller public class PlayersController { @@ -105,8 +106,14 @@ public String showGlobalRanking(Pageable pageable, Model model) { @GetMapping("/ranking/playerRanking") public String showPlayerRanking(Pageable pageable, Model model, Principal principal) { - Player player = playerService.getUserByUsername(principal.getName()).get(); - Page ranking = gameSessionService.getPlayerRanking(pageable, player); + Optional player = playerService.getUserByUsername(principal.getName()); + Player p = player.orElse(null); + + if (p == null) { + return "redirect:/login"; + } + + Page ranking = gameSessionService.getPlayerRanking(pageable, p); model.addAttribute("ranking", ranking.getContent()); model.addAttribute("page", ranking); diff --git a/src/main/java/com/uniovi/controllers/RestApiController.java b/src/main/java/com/uniovi/controllers/RestApiController.java deleted file mode 100644 index 27bb70a0..00000000 --- a/src/main/java/com/uniovi/controllers/RestApiController.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.uniovi.controllers; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.uniovi.entities.*; -import com.uniovi.repositories.GameSessionRepository; -import com.uniovi.services.ApiKeyService; -import com.uniovi.services.RestApiService; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import java.lang.reflect.Array; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Map; - -@RestController -public class RestApiController { - private final ApiKeyService apiKeyService; - private final RestApiService restApiService; - - @Autowired - public RestApiController(ApiKeyService apiKeyService, RestApiService restApiService) { - this.apiKeyService = apiKeyService; - this.restApiService = restApiService; - } - - @GetMapping("/api/players") - public String getPlayers(HttpServletResponse response, @RequestParam Map params) throws JsonProcessingException { - response.setContentType("application/json"); - ApiKey apiKey = getApiKeyFromParams(params); - if (apiKey == null) { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - ObjectMapper objectMapper = new ObjectMapper(); - Map error = Map.of("error", "Invalid API key"); - return objectMapper.writeValueAsString(error); - } - - List players = restApiService.getPlayers(params); - ObjectMapper objectMapper = new ObjectMapper(); - ObjectNode root = objectMapper.createObjectNode(); - ArrayNode arrayNode = objectMapper.createArrayNode(); - for (Player player : players) { - arrayNode.add(player.toJson()); - } - root.put("players", arrayNode); - restApiService.logAccess(apiKey, "/api/players", params); - return root.toString(); - } - - @GetMapping("/api/questions") - public String getQuestions(HttpServletResponse response, @RequestParam Map params) throws JsonProcessingException { - response.setContentType("application/json"); - ApiKey apiKey = getApiKeyFromParams(params); - if (apiKey == null) { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - ObjectMapper objectMapper = new ObjectMapper(); - Map error = Map.of("error", "Invalid API key"); - return objectMapper.writeValueAsString(error); - } - - ObjectMapper objectMapper = new ObjectMapper(); - ObjectNode root = objectMapper.createObjectNode(); - ArrayNode arrayNode = objectMapper.createArrayNode(); - List questions = restApiService.getQuestions(params); - for (Question question : questions) { - arrayNode.add(question.toJson()); - } - root.set("questions", arrayNode); - restApiService.logAccess(apiKey, "/api/questions", params); - return root.toString(); - } - - private ApiKey getApiKeyFromParams(Map params) { - if (!params.containsKey("apiKey")) { - return null; - } - - String apiKey = params.get("apiKey"); - return apiKeyService.getApiKey(apiKey); - } -} diff --git a/src/main/java/com/uniovi/controllers/api/PlayerApiController.java b/src/main/java/com/uniovi/controllers/api/PlayerApiController.java new file mode 100644 index 00000000..677cac9e --- /dev/null +++ b/src/main/java/com/uniovi/controllers/api/PlayerApiController.java @@ -0,0 +1,300 @@ +package com.uniovi.controllers.api; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.uniovi.dto.PlayerDto; +import com.uniovi.entities.*; +import com.uniovi.services.ApiKeyService; +import com.uniovi.services.PlayerService; +import com.uniovi.services.RestApiService; +import com.uniovi.validators.SignUpValidator; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.servers.Server; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.media.Content; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.validation.SimpleErrors; +import org.springframework.web.bind.annotation.*; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@OpenAPIDefinition(info = @Info(title = "Wikigame API", version = "1.0", description = "API for managing players and questions\nTo get access, please generate an API key in the webpage"), +servers = { + @Server(url = "https://wikigame.es", description = "Production server"), + @Server(url = "http://localhost:8080", description = "Local server"), +}) +@Tag(name = "Player API", description = "API for managing players") +@RestController +public class PlayerApiController { + private final ApiKeyService apiKeyService; + private final RestApiService restApiService; + private final SignUpValidator signUpValidator; + private final PlayerService playerService; + + @Autowired + public PlayerApiController(ApiKeyService apiKeyService, RestApiService restApiService, SignUpValidator signUpValidator, PlayerService playerService) { + this.apiKeyService = apiKeyService; + this.restApiService = restApiService; + this.signUpValidator = signUpValidator; + this.playerService = playerService; + } + + @Operation(summary = "Get players by various filters", description = "Fetch players based on the provided parameters such as username, email, id, roles.") + @Parameters({ + @Parameter(name = "apiKey", description = "API key for authentication", required = true), + @Parameter(name = "username", description = "Username of the player"), + @Parameter(name = "email", description = "Email of the player"), + @Parameter(name = "id", description = "ID of the player"), + @Parameter(name = "usernames", description = "Comma-separated list of usernames"), + @Parameter(name = "emails", description = "Comma-separated list of emails"), + @Parameter(name = "role", description = "Role of the player. Will return players that have this role."), + }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success", + content = {@Content(mediaType = "application/json", + examples = {@ExampleObject(name = "Example response", + value = "{\n" + + " \"players\":[\n" + + " {\n" + + " \"id\":1,\n" + + " \"username\":\"student1\",\n" + + " \"email\":\"student1@example.com\",\n" + + " \"roles\":[\n" + + " \"ROLE_USER\"\n" + + " ],\n" + + " \"gameSessions\":[\n" + + " {\n" + + " \"id\":1,\n" + + " \"player\":1,\n" + + " \"correctQuestions\":10,\n" + + " \"totalQuestions\":40,\n" + + " \"createdAt\":\"2024-03-04T22:44:41.067901\",\n" + + " \"finishTime\":\"2024-03-04T22:49:41.067901\",\n" + + " \"score\":0\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}")} + )}), + @ApiResponse(responseCode = "401", description = "Unauthorized if invalid api key", + content = @Content(mediaType = "application/json", examples = {@ExampleObject(name = "Error response", + value = "{\"error\":\"Invalid API key\"}" + )})) + }) + @GetMapping("/api/players") + public String getPlayers(HttpServletResponse response, @RequestParam @Parameter(hidden = true) Map params) throws JsonProcessingException { + response.setContentType("application/json"); + ApiKey apiKey = getApiKeyFromParams(params); + if (apiKey == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Invalid API key"); + return objectMapper.writeValueAsString(error); + } + + List players = restApiService.getPlayers(params); + ObjectMapper objectMapper = new ObjectMapper(); + ObjectNode root = objectMapper.createObjectNode(); + ArrayNode arrayNode = objectMapper.createArrayNode(); + for (Player player : players) { + arrayNode.add(player.toJson()); + } + root.put("players", arrayNode); + restApiService.logAccess(apiKey, "/api/players", params); + return root.toString(); + } + + + @Operation(summary = "Create a new player account") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success", + content = {@Content(mediaType = "application/json", + examples = {@ExampleObject(name = "Example response", + value = "{ \"success\" : true, \"id\": 1 }")} + )}), + @ApiResponse(responseCode = "401", description = "Unauthorized if invalid api key", + content = @Content(mediaType = "application/json", examples = {@ExampleObject(name = "Error response", + value = "{\"error\":\"Invalid API key\"}" + )})), + @ApiResponse(responseCode = "400", description = "Could not add user due to validation errors", + content = @Content(mediaType = "application/json", examples = {@ExampleObject(name = "Error response", + value = "{\"field1\":\"Error description in field 1\", \"field2\":\"Error description in field 2\"}" + )})) + }) + @PostMapping("/api/players") + public String addPlayer(@RequestHeader(name = "API-KEY") String apiKeyStr, + HttpServletResponse response, @RequestBody PlayerDto playerDto) throws JsonProcessingException { + response.setContentType("application/json"); + ApiKey apiKey = apiKeyService.getApiKey(apiKeyStr); + if (apiKey == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Invalid API key"); + return objectMapper.writeValueAsString(error); + } + + playerDto.setPasswordConfirm(playerDto.getPassword()); + + Errors err = new SimpleErrors(playerDto); + signUpValidator.validate(playerDto, err); + + if (err.hasErrors()) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode errorNode = objectMapper.createObjectNode(); + for (ObjectError error : err.getAllErrors()) { + ((ObjectNode) errorNode).put(((FieldError)error).getField(), error.getDefaultMessage()); + } + + return errorNode.toString(); + } + + Long id = playerService.addNewPlayer(playerDto).getId(); + + restApiService.logAccess(apiKey, "/api/players", Map.of("apiKey", apiKey.getKeyToken(), "user", playerDto.toString())); + return "{ \"success\" : true, \"id\": " + id + " }"; + } + + @Operation(summary = "Update a player account") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success", + content = {@Content(mediaType = "application/json", + examples = {@ExampleObject(name = "Example response", + value = "{ \"success\" : true }")} + )}), + @ApiResponse(responseCode = "401", description = "Unauthorized if invalid api key", + content = @Content(mediaType = "application/json", examples = {@ExampleObject(name = "Error response", + value = "{\"error\":\"Invalid API key\"}" + )})), + @ApiResponse(responseCode = "400", description = "Request body errors (check dropdown for more)", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Missing data", value = "{\"error\":\"No data provided\"}"), + @ExampleObject(name = "Invalid data", value = "{\"error\":\"Missing data or null data\"}"), + @ExampleObject(name = "Validation errors", value = "{\"field1\":\"Error description in field 1\", \"field2\":\"Error description in field 2\"}") + })), + @ApiResponse(responseCode = "404", description = "Player with the given ID not found", + content = @Content(mediaType = "application/json", examples = {@ExampleObject(name = "Error response", + value = "{\"error\":\"Player not found\"}" + )})) + }) + @PatchMapping("/api/players/{id}") + public String updatePlayer(@RequestHeader(name = "API-KEY") String apiKeyStr, + HttpServletResponse response, @PathVariable Long id, @RequestBody PlayerDto playerDto) throws JsonProcessingException { + response.setContentType("application/json"); + ApiKey apiKey = apiKeyService.getApiKey(apiKeyStr); + if (apiKey == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Invalid API key"); + return objectMapper.writeValueAsString(error); + } + + Optional player = playerService.getUser(id); + if (player.isEmpty()) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Player not found"); + return objectMapper.writeValueAsString(error); + } + + if (playerDto == null) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "No data provided"); + return objectMapper.writeValueAsString(error); + } + + if (playerDto.getUsername() == null || playerDto.getRoles() == null || playerDto.getEmail() == null || playerDto.getPassword() == null) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Missing data or null data"); + return objectMapper.writeValueAsString(error); + } + + playerDto.setPasswordConfirm(playerDto.getPassword()); + + Errors err = new SimpleErrors(playerDto); + signUpValidator.validate(playerDto, err); + + if (err.hasErrors()) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode errorNode = objectMapper.createObjectNode(); + for (ObjectError error : err.getAllErrors()) { + ((ObjectNode) errorNode).put(((FieldError)error).getField(), error.getDefaultMessage()); + } + + return errorNode.toString(); + } + + playerService.updatePlayer(id, playerDto); + return "{ \"success\" : true }"; + } + + @Operation(summary = "Delete a player account") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success", + content = {@Content(mediaType = "application/json", + examples = {@ExampleObject(name = "Example response", + value = "{ \"success\" : true }")} + )}), + @ApiResponse(responseCode = "401", description = "Unauthorized if invalid api key", + content = @Content(mediaType = "application/json", examples = {@ExampleObject(name = "Error response", + value = "{\"error\":\"Invalid API key\"}" + )})), + @ApiResponse(responseCode = "404", description = "Player with the given ID not found", + content = @Content(mediaType = "application/json", examples = {@ExampleObject(name = "Error response", + value = "{\"error\":\"Player not found\"}" + )})) + }) + @DeleteMapping("/api/players/{id}") + public String deletePlayer(@RequestHeader("API-KEY") String apiKeyStr, + HttpServletResponse response, @PathVariable Long id) throws JsonProcessingException { + response.setContentType("application/json"); + ApiKey apiKey = apiKeyService.getApiKey(apiKeyStr); + if (apiKey == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Invalid API key"); + return objectMapper.writeValueAsString(error); + } + + Optional player = playerService.getUser(id); + if (player.isEmpty()) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Player not found"); + return objectMapper.writeValueAsString(error); + } + + playerService.deletePlayer(id); + return "{ \"success\" : true }"; + } + + private ApiKey getApiKeyFromParams(Map params) { + if (!params.containsKey("apiKey")) { + return null; + } + + String apiKey = params.get("apiKey"); + return apiKeyService.getApiKey(apiKey); + } +} diff --git a/src/main/java/com/uniovi/controllers/api/QuestionsApiController.java b/src/main/java/com/uniovi/controllers/api/QuestionsApiController.java new file mode 100644 index 00000000..cdff40cf --- /dev/null +++ b/src/main/java/com/uniovi/controllers/api/QuestionsApiController.java @@ -0,0 +1,300 @@ +package com.uniovi.controllers.api; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.uniovi.dto.AnswerDto; +import com.uniovi.dto.QuestionDto; +import com.uniovi.entities.*; +import com.uniovi.services.ApiKeyService; +import com.uniovi.services.QuestionService; +import com.uniovi.services.RestApiService; +import com.uniovi.validators.QuestionValidator; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.media.Content; +import jakarta.servlet.http.HttpServletResponse; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.validation.SimpleErrors; +import org.springframework.web.bind.annotation.*; + +import org.springframework.data.domain.Pageable; +import java.util.List; + +import java.util.Map; + +@Tag(name = "Questions API", description = "API for managing questions") +@RestController +public class QuestionsApiController { + private final ApiKeyService apiKeyService; + private final RestApiService restApiService; + private final QuestionService questionService; + private final QuestionValidator questionValidator; + + @Autowired + public QuestionsApiController(ApiKeyService apiKeyService, RestApiService restApiService, QuestionService questionService, QuestionValidator questionValidator) { + this.apiKeyService = apiKeyService; + this.restApiService = restApiService; + this.questionService = questionService; + this.questionValidator = questionValidator; + } + + @Operation(summary = "Fetch questions, with different params available for management", description = "Fetch questions based on the provided parameters such as category, statement, id. The results are paged, and the page can be controlled with the page and size parameters.") + @Parameters({ + @Parameter(name = "apiKey", description = "API key for authentication", required = true), + @Parameter(name = "category", description = "Category of the question. Case sensitive"), + @Parameter(name = "statement", description = "Text contained in the statement of the question"), + @Parameter(name = "id", description = "ID of the question") + }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success", + content = {@Content(mediaType = "application/json", + examples = {@ExampleObject(name = "Example response", + value = "{\n" + + " \"questions\":[\n" + + " {\n" + + " \"id\":11802,\n" + + " \"statement\":\"Which countries share a border with Solomon Islands?\",\n" + + " \"category\":{\n" + + " \"id\":1,\n" + + " \"name\":\"Geography\",\n" + + " \"description\":\"Questions about geography\"\n" + + " },\n" + + " \"options\":[\n" + + " {\n" + + " \"id\":46252,\n" + + " \"text\":\"Papua New Guinea\",\n" + + " \"correct\":true,\n" + + " \"question\":11802\n" + + " },\n" + + " {\n" + + " \"id\":46253,\n" + + " \"text\":\"Venezuela\",\n" + + " \"correct\":false,\n" + + " \"question\":11802\n" + + " },\n" + + " {\n" + + " \"id\":46254,\n" + + " \"text\":\"Austria\",\n" + + " \"correct\":false,\n" + + " \"question\":11802\n" + + " },\n" + + " {\n" + + " \"id\":46255,\n" + + " \"text\":\"United States of America\",\n" + + " \"correct\":false,\n" + + " \"question\":11802\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}")} + )}), + @ApiResponse(responseCode = "401", description = "Unauthorized if invalid api key", + content = @Content(mediaType = "application/json", examples = {@ExampleObject(name = "Error response", + value = "{\"error\":\"Invalid API key\"}" + )})) + }) + @GetMapping("/api/questions") + public String getQuestions(@ParameterObject Pageable pageable, HttpServletResponse response, @RequestParam @Parameter(hidden = true) Map params) throws JsonProcessingException { + response.setContentType("application/json"); + ApiKey apiKey = getApiKeyFromParams(params); + if (apiKey == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Invalid API key"); + return objectMapper.writeValueAsString(error); + } + + ObjectMapper objectMapper = new ObjectMapper(); + ObjectNode root = objectMapper.createObjectNode(); + ArrayNode arrayNode = objectMapper.createArrayNode(); + List questions = restApiService.getQuestions(params, pageable); + for (Question question : questions) { + arrayNode.add(question.toJson()); + } + root.set("questions", arrayNode); + restApiService.logAccess(apiKey, "/api/questions", params); + return root.toString(); + } + + @Operation(summary = "Add a new question", description = "Add a new question to the database. The question must have a statement, a category, and 4 options. The correct option must be marked as such.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success", + content = {@Content(mediaType = "application/json", + examples = {@ExampleObject(name = "Example response", + value = "{\"success\": true, \"id\": 1}" + )} + )}), + @ApiResponse(responseCode = "400", description = "Bad request if the data is missing or invalid", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Error response", value = "{\"error\":\"Missing data\"}"), + @ExampleObject(name = "Validation errors", value = "{\"field1\":\"Error description in field 1\", \"field2\":\"Error description in field 2\"}") + })) + }) + @PostMapping("/api/questions") + public String addQuestion(HttpServletResponse response, @RequestHeader("API-KEY") String apiKeyStr, @RequestBody QuestionDto questionDto) throws JsonProcessingException { + ApiKey apiKey = apiKeyService.getApiKey(apiKeyStr); + if (apiKey == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Invalid API key"); + return objectMapper.writeValueAsString(error); + } + + if (questionDto == null) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Missing data"); + return objectMapper.writeValueAsString(error); + } + + if (questionDto.getOptions().stream().anyMatch(option -> option.isCorrect())) { + questionDto.setCorrectAnswer(questionDto.getOptions().stream().filter(option -> option.isCorrect()).findFirst().get()); + } + + Errors err = new SimpleErrors(questionDto); + questionValidator.validate(questionDto, err); + + if (err.hasErrors()) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode errorNode = objectMapper.createObjectNode(); + for (ObjectError error : err.getAllErrors()) { + ((ObjectNode) errorNode).put(((FieldError)error).getField(), error.getDefaultMessage()); + } + + return errorNode.toString(); + } + + Question q = questionService.addNewQuestion(questionDto); + + restApiService.logAccess(apiKey, "/api/questions", Map.of("apiKey", apiKeyStr, "question", questionDto.toString())); + return "{ \"success\": true, \"id\":" + q.getId() + " }"; + } + + @Operation(summary = "Update a question", description = "Update a question in the database. The question must have a statement, a category, and 4 options. The correct option must be marked as such.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success", + content = {@Content(mediaType = "application/json", + examples = {@ExampleObject(name = "Example response", + value = "{\"success\": true}" + )} + )}), + @ApiResponse(responseCode = "400", description = "Bad request if the data is missing or invalid", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Error response", value = "{\"error\":\"Missing data\"}"), + @ExampleObject(name = "Validation errors", value = "{\"field1\":\"Error description in field 1\", \"field2\":\"Error description in field 2\"}") + })), + @ApiResponse(responseCode = "404", description = "Not found if the question does not exist", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Error response", value = "{\"error\":\"Question not found\"}") + })) + }) + @PatchMapping("/api/questions/{id}") + public String updateQuestion(HttpServletResponse response, @RequestHeader("API-KEY") String apiKeyStr, + @PathVariable Long id, @RequestBody QuestionDto questionDto) throws JsonProcessingException { + ApiKey apiKey = apiKeyService.getApiKey(apiKeyStr); + if (apiKey == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Invalid API key"); + return objectMapper.writeValueAsString(error); + } + + Question q = questionService.getQuestion(id).orElse(null); + if (q == null) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Question not found"); + return objectMapper.writeValueAsString(error); + } + + if (questionDto == null) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Missing data"); + return objectMapper.writeValueAsString(error); + } + + if (questionDto.getOptions().stream().anyMatch(AnswerDto::isCorrect)) { + questionDto.setCorrectAnswer(questionDto.getOptions().stream().filter(option -> option.isCorrect()).findFirst().get()); + } + + Errors err = new SimpleErrors(questionDto); + questionValidator.validate(questionDto, err); + + if (err.hasErrors()) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode errorNode = objectMapper.createObjectNode(); + for (ObjectError error : err.getAllErrors()) { + ((ObjectNode) errorNode).put(((FieldError) error).getField(), error.getDefaultMessage()); + } + + return errorNode.toString(); + } + + questionService.updateQuestion(id, questionDto); + return "{ \"success\": true }"; + } + + @Operation(summary = "Delete a question", description = "Delete a question from the database") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success", + content = {@Content(mediaType = "application/json", + examples = {@ExampleObject(name = "Example response", + value = "{\"success\": true}" + )} + )}), + @ApiResponse(responseCode = "404", description = "Not found if the question does not exist", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Error response", value = "{\"error\":\"Question not found\"}") + })), + @ApiResponse(responseCode = "401", description = "Unauthorized if invalid api key", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Error response", value = "{\"error\":\"Invalid API key\"}") + })) + }) + @DeleteMapping("/api/questions/{id}") + public String deleteQuestion(HttpServletResponse response, @RequestHeader("API-KEY") String apiKeyStr, @PathVariable Long id) throws JsonProcessingException { + ApiKey apiKey = apiKeyService.getApiKey(apiKeyStr); + if (apiKey == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Invalid API key"); + return objectMapper.writeValueAsString(error); + } + + Question q = questionService.getQuestion(id).orElse(null); + if (q == null) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + ObjectMapper objectMapper = new ObjectMapper(); + Map error = Map.of("error", "Question not found"); + return objectMapper.writeValueAsString(error); + } + + questionService.deleteQuestion(id); + return "{ \"success\": true }"; + } + + private ApiKey getApiKeyFromParams(Map params) { + if (!params.containsKey("apiKey")) { + return null; + } + + String apiKey = params.get("apiKey"); + return apiKeyService.getApiKey(apiKey); + } +} diff --git a/src/main/java/com/uniovi/dto/AnswerDto.java b/src/main/java/com/uniovi/dto/AnswerDto.java index 20ad1e37..026eede6 100644 --- a/src/main/java/com/uniovi/dto/AnswerDto.java +++ b/src/main/java/com/uniovi/dto/AnswerDto.java @@ -1,17 +1,18 @@ package com.uniovi.dto; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; @Getter @Setter -@AllArgsConstructor @NoArgsConstructor +@ToString public class AnswerDto { - private Long id; + + @Schema(description = "The text of the answer", example = "The answer text") private String text; + + @Schema(description = "Whether the answer is correct or not", example = "true") private boolean correct; } diff --git a/src/main/java/com/uniovi/dto/CategoryDto.java b/src/main/java/com/uniovi/dto/CategoryDto.java index 6b34b07e..fc87530e 100644 --- a/src/main/java/com/uniovi/dto/CategoryDto.java +++ b/src/main/java/com/uniovi/dto/CategoryDto.java @@ -1,5 +1,6 @@ package com.uniovi.dto; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -9,12 +10,15 @@ @Getter @Setter -@AllArgsConstructor @NoArgsConstructor public class CategoryDto { - private Long id; + @Schema(description = "The name of the category", example = "Geography") private String name; + + @Schema(description = "The description of the category", example = "Questions about the world", hidden = true) private String description; + + @Schema(description = "The list of questions in the category", hidden = true) private List questions; } diff --git a/src/main/java/com/uniovi/dto/PlayerDto.java b/src/main/java/com/uniovi/dto/PlayerDto.java index 3b7a90b8..027b26fa 100644 --- a/src/main/java/com/uniovi/dto/PlayerDto.java +++ b/src/main/java/com/uniovi/dto/PlayerDto.java @@ -1,18 +1,27 @@ package com.uniovi.dto; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; @Getter @Setter -@AllArgsConstructor @NoArgsConstructor +@AllArgsConstructor +@ToString public class PlayerDto { + + @Schema(description = "Username of the player", example = "student1") private String username; + + @Schema(description = "Email of the player", example = "student1@email.com") private String email; + + @Schema(description = "Password of the player", example = "password") private String password; + + @Schema(hidden = true) private String passwordConfirm; + + @Schema(description = "Roles of the player", example = "[\"ROLE_USER\"]") private String[] roles; } diff --git a/src/main/java/com/uniovi/dto/QuestionDto.java b/src/main/java/com/uniovi/dto/QuestionDto.java index dac83779..d97efb5f 100644 --- a/src/main/java/com/uniovi/dto/QuestionDto.java +++ b/src/main/java/com/uniovi/dto/QuestionDto.java @@ -1,9 +1,7 @@ package com.uniovi.dto; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; import java.util.List; @@ -11,12 +9,21 @@ @Setter @AllArgsConstructor @NoArgsConstructor +@ToString public class QuestionDto { - private Long id; + @Schema(description = "The statement of the question") private String statement; + + @Schema(description = "The options of the question") private List options; + + @Schema(description = "The correct answer of the question", hidden = true) private AnswerDto correctAnswer; + + @Schema(description = "The category of the question") private CategoryDto category; + @Schema(description = "The language of the question") + private String language; } diff --git a/src/main/java/com/uniovi/dto/RoleDto.java b/src/main/java/com/uniovi/dto/RoleDto.java index 23565a2d..719dd01d 100644 --- a/src/main/java/com/uniovi/dto/RoleDto.java +++ b/src/main/java/com/uniovi/dto/RoleDto.java @@ -1,14 +1,12 @@ package com.uniovi.dto; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; @Getter -@Setter @AllArgsConstructor -@NoArgsConstructor public class RoleDto { + + @Schema(description = "The name of the role", example = "ROLE_USER") private String name; } diff --git a/src/main/java/com/uniovi/entities/Answer.java b/src/main/java/com/uniovi/entities/Answer.java index a9528dba..6af60ba4 100644 --- a/src/main/java/com/uniovi/entities/Answer.java +++ b/src/main/java/com/uniovi/entities/Answer.java @@ -1,6 +1,5 @@ package com.uniovi.entities; -import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -28,7 +27,7 @@ public class Answer implements JsonEntity { private boolean correct; @JsonIgnore - @ManyToOne + @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH) private Question question; public Answer(String text, boolean correct) { diff --git a/src/main/java/com/uniovi/entities/ApiKey.java b/src/main/java/com/uniovi/entities/ApiKey.java index 43f65b89..b3233b1b 100644 --- a/src/main/java/com/uniovi/entities/ApiKey.java +++ b/src/main/java/com/uniovi/entities/ApiKey.java @@ -24,6 +24,6 @@ public class ApiKey { @OneToOne private Player player; - @OneToMany(mappedBy = "apiKey") + @OneToMany(mappedBy = "apiKey", cascade = CascadeType.ALL, orphanRemoval = true) private Set accessLogs = new HashSet<>(); } diff --git a/src/main/java/com/uniovi/entities/Associations.java b/src/main/java/com/uniovi/entities/Associations.java index 28493169..73218e2f 100644 --- a/src/main/java/com/uniovi/entities/Associations.java +++ b/src/main/java/com/uniovi/entities/Associations.java @@ -121,10 +121,40 @@ public static void addAnswer(Question question, List answer) { * @param answer The answer */ public static void removeAnswer(Question question, List answer) { - question.getOptions().remove(answer); + question.getOptions().removeAll(answer); for (Answer a : answer) { a.setQuestion(null); } } + //public static void removeAnswer(Question question, List answer) { + // question.getOptions().remove(answer); + //for (Answer a : answer) { + // a.setQuestion(null); + //} + //} + } + + public static class QuestionsCategory { + /** + * Add a new association between a question and a category + * + * @param question The question + * @param category The category + */ + public static void addCategory(Question question, Category category) { + question.setCategory(category); + category.getQuestions().add(question); + } + + /** + * Remove an association between a question and a category + * + * @param question The question + * @param category The category + */ + public static void removeCategory(Question question, Category category) { + category.getQuestions().remove(question); + question.setCategory(null); + } } } diff --git a/src/main/java/com/uniovi/entities/Category.java b/src/main/java/com/uniovi/entities/Category.java index c368e762..28e798c3 100644 --- a/src/main/java/com/uniovi/entities/Category.java +++ b/src/main/java/com/uniovi/entities/Category.java @@ -25,7 +25,7 @@ public class Category implements JsonEntity { private String name; private String description; - @OneToMany(mappedBy = "category") + @OneToMany(mappedBy = "category", fetch = FetchType.EAGER) private Set questions = new HashSet<>(); public Category(String name, String description) { diff --git a/src/main/java/com/uniovi/entities/GameSession.java b/src/main/java/com/uniovi/entities/GameSession.java index 1a7f7fa3..a4285788 100644 --- a/src/main/java/com/uniovi/entities/GameSession.java +++ b/src/main/java/com/uniovi/entities/GameSession.java @@ -9,6 +9,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; +import java.io.Serializable; import java.time.Duration; import java.time.LocalDateTime; import java.util.*; @@ -17,7 +18,7 @@ @Setter @Entity @NoArgsConstructor -public class GameSession implements JsonEntity { +public class GameSession implements JsonEntity, Serializable { @Id @GeneratedValue private Long id; diff --git a/src/main/java/com/uniovi/entities/Player.java b/src/main/java/com/uniovi/entities/Player.java index 824290ef..491a8bd8 100644 --- a/src/main/java/com/uniovi/entities/Player.java +++ b/src/main/java/com/uniovi/entities/Player.java @@ -33,7 +33,7 @@ public class Player implements JsonEntity { @NotEmpty private String password; - @ManyToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER) + @ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER) private Set roles = new HashSet<>(); @OneToMany(mappedBy = "player", cascade = CascadeType.ALL, fetch = FetchType.EAGER) diff --git a/src/main/java/com/uniovi/entities/Question.java b/src/main/java/com/uniovi/entities/Question.java index 27dc8dbc..10ac54f3 100644 --- a/src/main/java/com/uniovi/entities/Question.java +++ b/src/main/java/com/uniovi/entities/Question.java @@ -23,6 +23,8 @@ public class Question implements JsonEntity { public static final String ENGLISH = "en"; public static final String SPANISH = "es"; + public static final String FRENCH = "fr"; + @Id @GeneratedValue @@ -31,10 +33,10 @@ public class Question implements JsonEntity { @Column(unique = false) private String statement; - @OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) + @OneToMany(mappedBy = "question", cascade = CascadeType.ALL, fetch = FetchType.EAGER) private List options = new ArrayList<>(); - @OneToOne + @OneToOne(cascade = CascadeType.ALL) private Answer correctAnswer; @ManyToOne diff --git a/src/main/java/com/uniovi/entities/RestApiAccessLog.java b/src/main/java/com/uniovi/entities/RestApiAccessLog.java index bf5df136..e0c55b2e 100644 --- a/src/main/java/com/uniovi/entities/RestApiAccessLog.java +++ b/src/main/java/com/uniovi/entities/RestApiAccessLog.java @@ -1,9 +1,6 @@ package com.uniovi.entities; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -23,5 +20,7 @@ public class RestApiAccessLog { private ApiKey apiKey; private String path; + + @Column(columnDefinition = "VARCHAR(10000)") private String details; } diff --git a/src/main/java/com/uniovi/entities/Role.java b/src/main/java/com/uniovi/entities/Role.java index deaa4b6a..c767c425 100644 --- a/src/main/java/com/uniovi/entities/Role.java +++ b/src/main/java/com/uniovi/entities/Role.java @@ -16,7 +16,7 @@ public class Role { @Id private String name; - @ManyToMany(mappedBy = "roles") + @ManyToMany(mappedBy = "roles", fetch = FetchType.EAGER) private Set players = new HashSet<>(); public Role(String name) { diff --git a/src/main/java/com/uniovi/repositories/GameSessionRepository.java b/src/main/java/com/uniovi/repositories/GameSessionRepository.java index 9575c971..996e9e55 100644 --- a/src/main/java/com/uniovi/repositories/GameSessionRepository.java +++ b/src/main/java/com/uniovi/repositories/GameSessionRepository.java @@ -1,13 +1,11 @@ package com.uniovi.repositories; -import com.uniovi.entities.Answer; import com.uniovi.entities.GameSession; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.CrudRepository; - import com.uniovi.entities.Player; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; import java.util.List; diff --git a/src/main/java/com/uniovi/repositories/QuestionRepository.java b/src/main/java/com/uniovi/repositories/QuestionRepository.java index 16bd18dd..e7dfa216 100644 --- a/src/main/java/com/uniovi/repositories/QuestionRepository.java +++ b/src/main/java/com/uniovi/repositories/QuestionRepository.java @@ -1,5 +1,6 @@ package com.uniovi.repositories; +import com.uniovi.entities.Category; import com.uniovi.entities.Question; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -14,4 +15,10 @@ public interface QuestionRepository extends CrudRepository { @Query("SELECT q FROM Question q WHERE q.language = ?1") Page findByLanguage(Pageable pageable, String language); + + @Query("SELECT q FROM Question q WHERE q.category = ?1 AND q.language = ?2") + Page findByCategoryAndLanguage(Pageable pageable, Category category, String lang); + + @Query("SELECT q FROM Question q WHERE LOWER(q.statement) LIKE LOWER(CONCAT('%', ?1, '%')) AND q.language = ?2") + Page findByStatementAndLanguage(Pageable pageable, String statement, String language); } diff --git a/src/main/java/com/uniovi/services/InsertSampleDataService.java b/src/main/java/com/uniovi/services/InsertSampleDataService.java index 71253e4e..f51a0ed8 100644 --- a/src/main/java/com/uniovi/services/InsertSampleDataService.java +++ b/src/main/java/com/uniovi/services/InsertSampleDataService.java @@ -19,8 +19,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; +import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; +import java.io.IOException; import java.time.LocalDateTime; import java.util.*; @@ -31,22 +33,24 @@ public class InsertSampleDataService { private final CategoryService categoryService; private final QuestionRepository questionRepository; private final GameSessionRepository gameSessionRepository; + private Environment environment; - private Logger log = LoggerFactory.getLogger(InsertSampleDataService.class);; + private Logger log = LoggerFactory.getLogger(InsertSampleDataService.class); public InsertSampleDataService(PlayerService playerService, QuestionService questionService, CategoryService categoryService, QuestionRepository questionRepository, - GameSessionRepository gameSessionRepository) { + GameSessionRepository gameSessionRepository, Environment environment) { this.playerService = playerService; this.questionService = questionService; this.categoryService = categoryService; this.questionRepository = questionRepository; this.gameSessionRepository = gameSessionRepository; + this.environment = environment; } @Transactional @EventListener(ApplicationReadyEvent.class) // Uncomment this line to insert sample data on startup - public void insertSampleQuestions() { + public void insertSampleQuestions() throws InterruptedException, IOException { if (!playerService.getUserByEmail("test@test.com").isPresent()) { PlayerDto player = new PlayerDto(); player.setEmail("test@test.com"); @@ -56,6 +60,23 @@ public void insertSampleQuestions() { playerService.generateApiKey(playerService.addNewPlayer(player)); } + if (Arrays.stream(environment.getActiveProfiles()).anyMatch(env -> (env.equalsIgnoreCase("test")))) { + log.info("Test profile active, skipping sample data insertion"); + return; + } + + generateSampleData(); + } + + @Transactional + public void generateTestQuestions() { + questionRepository.deleteAll(); + questionService.testQuestions(4); + } + + @Transactional + public void generateSampleData() throws InterruptedException, IOException { + questionRepository.deleteAll(); MultipleQuestionGenerator allQuestionGenerator = new MultipleQuestionGenerator( @@ -74,6 +95,14 @@ public void insertSampleQuestions() { List questionsEs = allQuestionGenerator.getQuestions(); questionsEs.forEach(questionService::addNewQuestion); + allQuestionGenerator = new MultipleQuestionGenerator( + new ContinentQuestionGeneration(categoryService, Question.FRENCH), + new CapitalQuestionGenerator(categoryService, Question.FRENCH), + new BorderQuestionGenerator(categoryService, Question.FRENCH) + ); + List questionsFr = allQuestionGenerator.getQuestions(); + questionsFr.forEach(questionService::addNewQuestion); + log.info("Sample questions inserted"); } } diff --git a/src/main/java/com/uniovi/services/PlayerService.java b/src/main/java/com/uniovi/services/PlayerService.java index a66c661f..f59669e3 100644 --- a/src/main/java/com/uniovi/services/PlayerService.java +++ b/src/main/java/com/uniovi/services/PlayerService.java @@ -59,4 +59,17 @@ public interface PlayerService { * @param player The player to generate the API key for */ void generateApiKey(Player player); + + /** + * Update the information of a player + * @param id The id of the player to update + * @param playerDto The new information of the player + */ + void updatePlayer(Long id, PlayerDto playerDto); + + /** + * Delete a player from the database + * @param id The id of the player to delete + */ + void deletePlayer(Long id); } diff --git a/src/main/java/com/uniovi/services/QuestionService.java b/src/main/java/com/uniovi/services/QuestionService.java index c89a3ae9..7eb7d422 100644 --- a/src/main/java/com/uniovi/services/QuestionService.java +++ b/src/main/java/com/uniovi/services/QuestionService.java @@ -1,9 +1,13 @@ package com.uniovi.services; import com.uniovi.dto.QuestionDto; +import com.uniovi.entities.Category; import com.uniovi.entities.Question; +import jakarta.transaction.Transactional; +import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; +import org.springframework.data.domain.Pageable; import java.util.List; import java.util.Optional; @@ -17,6 +21,13 @@ public interface QuestionService { */ void addNewQuestion(Question question); + /** + * Add a new question to the database + * + * @param question Question to be added + */ + Question addNewQuestion(QuestionDto question); + /** * Get all the questions in the database * @@ -24,6 +35,14 @@ public interface QuestionService { */ List getAllQuestions(); + /** + * Get a page with all the questions in the database + * + * @param pageable The page to get + * @return A page with all the questions + */ + Page getQuestions(Pageable pageable); + /** * Get a question by its id * @@ -47,4 +66,43 @@ public interface QuestionService { * @return True if the answer is correct, false otherwise */ boolean checkAnswer(Long idquestion, Long idanswer); + + /** + * Get the questions of a category + * @param pageable The page to get + * @param category The category of the questions + * @param lang The language of the questions + * @return The questions of the category + */ + List getQuestionsByCategory(Pageable pageable, Category category, String lang); + + /** + * Get the questions with a statement that contains the given string + * @param pageable The page to get + * @param statement The string to search + * @param lang The language of the questions + * @return The questions with the statement that contains the string + */ + List getQuestionsByStatement(Pageable pageable, String statement, String lang); + + /** + * Update a question + * @param id The id of the question to update + * @param questionDto The new data of the question + */ + void updateQuestion(Long id, QuestionDto questionDto); + + /** + * Delete a question + * @param id The id of the question to delete + */ + void deleteQuestion(Long id); + + /** + * Get some test questions + * + * @param num The number of questions to get + * @return The questions selected + */ + List testQuestions(int num); } diff --git a/src/main/java/com/uniovi/services/RestApiService.java b/src/main/java/com/uniovi/services/RestApiService.java index 9b8570e4..a0ca59c2 100644 --- a/src/main/java/com/uniovi/services/RestApiService.java +++ b/src/main/java/com/uniovi/services/RestApiService.java @@ -4,6 +4,7 @@ import com.uniovi.entities.Player; import com.uniovi.entities.Question; +import org.springframework.data.domain.Pageable; import java.util.List; import java.util.Map; @@ -28,5 +29,5 @@ public interface RestApiService { * @param params A map with the parameters of the request * @return A list with all the questions */ - List getQuestions(Map params); + List getQuestions(Map params, Pageable pageable); } diff --git a/src/main/java/com/uniovi/services/RoleService.java b/src/main/java/com/uniovi/services/RoleService.java index ae094f14..e620105f 100644 --- a/src/main/java/com/uniovi/services/RoleService.java +++ b/src/main/java/com/uniovi/services/RoleService.java @@ -20,10 +20,4 @@ public interface RoleService { * @return The role with the given name */ Role getRole(String name); - - /** - * Get all the roles in the database - * @return A list with all the roles - */ - List getRoles(); } diff --git a/src/main/java/com/uniovi/services/impl/GameSessionImpl.java b/src/main/java/com/uniovi/services/impl/GameSessionImpl.java index bed23a3f..d7e2ad3a 100644 --- a/src/main/java/com/uniovi/services/impl/GameSessionImpl.java +++ b/src/main/java/com/uniovi/services/impl/GameSessionImpl.java @@ -16,7 +16,7 @@ @Service public class GameSessionImpl implements GameSessionService { - public static final Integer NORMAL_GAME_QUESTION_NUM = 20; + public static final Integer NORMAL_GAME_QUESTION_NUM = 4; private final GameSessionRepository gameSessionRepository; private final QuestionService questionService; diff --git a/src/main/java/com/uniovi/services/impl/PlayerServiceImpl.java b/src/main/java/com/uniovi/services/impl/PlayerServiceImpl.java index b928c030..f4fa462d 100644 --- a/src/main/java/com/uniovi/services/impl/PlayerServiceImpl.java +++ b/src/main/java/com/uniovi/services/impl/PlayerServiceImpl.java @@ -102,4 +102,38 @@ public void generateApiKey(Player player) { System.out.println("Generated API key for " + player.getUsername() + ": " + apiKey.getKeyToken()); playerRepository.save(player); } + + @Override + public void updatePlayer(Long id, PlayerDto playerDto) { + Optional player = playerRepository.findById(id); + if (player.isEmpty()) + return; + + Player p = player.get(); + if (playerDto.getEmail() != null) + p.setEmail(playerDto.getEmail()); + if (playerDto.getUsername() != null) + p.setUsername(playerDto.getUsername()); + if (playerDto.getPassword() != null) + p.setPassword(passwordEncoder.encode(playerDto.getPassword())); + if (playerDto.getRoles() != null) { + p.getRoles().clear(); + for (String roleStr : playerDto.getRoles()) { + Role r = roleService.getRole(roleStr); + if (r != null) + Associations.PlayerRole.addRole(p, r); + else { + r = roleService.addRole(new RoleDto(roleStr)); + Associations.PlayerRole.addRole(p, r); + } + } + } + + playerRepository.save(p); + } + + @Override + public void deletePlayer(Long id) { + playerRepository.deleteById(id); + } } diff --git a/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java b/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java index d45c1b5f..f0ec9f7e 100644 --- a/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java +++ b/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java @@ -1,27 +1,50 @@ package com.uniovi.services.impl; +import com.uniovi.dto.QuestionDto; +import com.uniovi.entities.Answer; +import com.uniovi.entities.Associations; +import com.uniovi.entities.Category; import com.uniovi.entities.Question; +import com.uniovi.repositories.AnswerRepository; import com.uniovi.repositories.QuestionRepository; +import com.uniovi.services.AnswerService; +import com.uniovi.services.CategoryService; import com.uniovi.services.QuestionService; +import jakarta.persistence.EntityManager; +import jakarta.transaction.Transactional; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; import org.springframework.data.querydsl.QPageRequest; import org.springframework.stereotype.Service; +import java.security.SecureRandom; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.Random; +import org.springframework.data.domain.Pageable; @Service public class QuestionServiceImpl implements QuestionService { - private final QuestionRepository questionRepository; + private final CategoryService categoryService; + private final AnswerService answerService; + private final AnswerRepository answerRepository; + private final EntityManager entityManager; - public QuestionServiceImpl(QuestionRepository questionRepository) { + private final Random random = new SecureRandom(); + + public QuestionServiceImpl(QuestionRepository questionRepository, CategoryService categoryService, + AnswerService answerService, AnswerRepository answerRepository, + EntityManager entityManager) { this.questionRepository = questionRepository; + this.categoryService = categoryService; + this.answerService = answerService; + this.answerRepository = answerRepository; + this.entityManager = entityManager; } @Override @@ -29,13 +52,44 @@ public void addNewQuestion(Question question) { questionRepository.save(question); } + @Override + public Question addNewQuestion(QuestionDto question) { + Category category = categoryService.getCategoryByName(question.getCategory().getName()); + if (category == null) { + categoryService.addNewCategory(new Category(question.getCategory().getName(), question.getCategory().getDescription())); + category = categoryService.getCategoryByName(question.getCategory().getName()); + } + + List answers = new ArrayList<>(); + for (int i = 0; i < question.getOptions().size(); i++) { + Answer a = new Answer(); + a.setText(question.getOptions().get(i).getText()); + a.setCorrect(question.getOptions().get(i).isCorrect()); + answerService.addNewAnswer(a); + answers.add(a); + } + + Question q = new Question(); + q.setStatement(question.getStatement()); + q.setLanguage(question.getLanguage()); + Associations.QuestionsCategory.addCategory(q, category); + Associations.QuestionAnswers.addAnswer(q, answers); + addNewQuestion(q); + + return q; + } + @Override public List getAllQuestions() { - List l = new ArrayList<>(); - questionRepository.findAll().forEach(l::add); + List l = new ArrayList<>(questionRepository.findAll()); return l; } + @Override + public Page getQuestions(Pageable pageable) { + return questionRepository.findByLanguage(pageable, LocaleContextHolder.getLocale().getLanguage()); + } + @Override public Optional getQuestion(Long id) { return questionRepository.findById(id); @@ -47,9 +101,9 @@ public List getRandomQuestions(int num) { .filter(question -> question.getLanguage().equals(LocaleContextHolder.getLocale().getLanguage())).toList(); List res = new ArrayList<>(); for (int i = 0; i < num; i++) { - int idx = (int) (Math.random() * allQuestions.size()); - while (allQuestions.get(idx).hasEmptyOptions()){ - idx = (int) (Math.random() * allQuestions.size()); + int idx = random.nextInt(allQuestions.size()); + while (allQuestions.get(idx).hasEmptyOptions() || res.contains(allQuestions.get(idx))){ + idx = random.nextInt(allQuestions.size()); } res.add(allQuestions.get(idx)); } @@ -65,4 +119,81 @@ public boolean checkAnswer(Long idquestion, Long idanswer) { return false; } + @Override + public List getQuestionsByCategory(Pageable pageable, Category category, String lang) { + return questionRepository.findByCategoryAndLanguage(pageable, category, lang).toList(); + } + + @Override + public List getQuestionsByStatement(Pageable pageable, String statement, String lang) { + return questionRepository.findByStatementAndLanguage(pageable, statement, lang).toList(); + } + + @Override + public void updateQuestion(Long id, QuestionDto questionDto) { + Optional q = questionRepository.findById(id); + if (q.isPresent()) { + entityManager.clear(); + Question question = q.get(); + question.setStatement(questionDto.getStatement()); + question.setLanguage(questionDto.getLanguage()); + Category category = categoryService.getCategoryByName(questionDto.getCategory().getName()); + if (category == null) { + categoryService.addNewCategory(new Category(questionDto.getCategory().getName(), questionDto.getCategory().getDescription())); + category = categoryService.getCategoryByName(questionDto.getCategory().getName()); + } + + Associations.QuestionsCategory.removeCategory(question, question.getCategory()); + + for (int i = 0; i < questionDto.getOptions().size(); i++) { + Answer a = question.getOption(i); + a.setText(questionDto.getOptions().get(i).getText()); + a.setCorrect(questionDto.getOptions().get(i).isCorrect()); + } + + Associations.QuestionsCategory.addCategory(question, category); + questionRepository.save(question); + } + } + + @Override + @Transactional + public void deleteQuestion(Long id) { + Optional q = questionRepository.findById(id); + if (q.isPresent()) { + Question question = q.get(); + answerRepository.deleteAll(question.getOptions()); + Associations.QuestionAnswers.removeAnswer(question, question.getOptions()); + Associations.QuestionsCategory.removeCategory(question, question.getCategory()); + q.get().setCorrectAnswer(null); + questionRepository.delete(question); + } + } + + @Override + public List testQuestions(int num) { + List res = new ArrayList<>(); + Category c = new Category("Test category", "Test category"); + categoryService.addNewCategory(c); + for (int i = 0; i < num; i++) { + Question q = new Question(); + q.setStatement("Test question " + i); + q.setLanguage(LocaleContextHolder.getLocale().getLanguage()); + Associations.QuestionsCategory.addCategory(q, c); + List answers = new ArrayList<>(); + for (int j = 0; j < 4; j++) { + Answer a = new Answer(); + a.setText("Test answer " + j); + a.setCorrect(j == 0); + if(j==0) q.setCorrectAnswer(a); + answerService.addNewAnswer(a); + answers.add(a); + } + Associations.QuestionAnswers.addAnswer(q, answers); + addNewQuestion(q); + res.add(q); + } + return res; + } + } diff --git a/src/main/java/com/uniovi/services/impl/RestApiServiceImpl.java b/src/main/java/com/uniovi/services/impl/RestApiServiceImpl.java index 9661f69e..3ff29db6 100644 --- a/src/main/java/com/uniovi/services/impl/RestApiServiceImpl.java +++ b/src/main/java/com/uniovi/services/impl/RestApiServiceImpl.java @@ -3,18 +3,17 @@ import com.mysql.cj.util.StringUtils; import com.uniovi.entities.*; import com.uniovi.repositories.RestApiLogRepository; -import com.uniovi.services.ApiKeyService; +import com.uniovi.services.CategoryService; import com.uniovi.services.PlayerService; import com.uniovi.services.QuestionService; import com.uniovi.services.RestApiService; import jakarta.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import org.springframework.data.domain.Pageable; +import java.util.*; @Service @Transactional // makes hibernate open transaction context automatically to avoid lazy-loading issues @@ -22,74 +21,77 @@ public class RestApiServiceImpl implements RestApiService { private final PlayerService playerService; private final RestApiLogRepository restApiLogRepository; private final QuestionService questionService; + private final CategoryService categoryService; @Autowired public RestApiServiceImpl(PlayerService playerService, RestApiLogRepository restApiLogRepository, - QuestionService questionService) { + QuestionService questionService, CategoryService categoryService) { this.playerService = playerService; this.restApiLogRepository = restApiLogRepository; this.questionService = questionService; + this.categoryService = categoryService; } @Override public List getPlayers(Map params) { + if (params.size() == 1) + return playerService.getUsers(); + + boolean ranOtherParams = false; + + + Set players = new HashSet<>(); if (params.containsKey("username")) { + ranOtherParams = true; Optional found = playerService.getUserByUsername(params.get("username")); - if (found.isPresent()) - return List.of(found.get()); - else - return List.of(); + found.ifPresent(players::add); } if (params.containsKey("email")) { + ranOtherParams = true; Optional found = playerService.getUserByEmail(params.get("email")); - if (found.isPresent()) - return List.of(found.get()); - else - return List.of(); - } - - if (params.containsKey("role")) { - return playerService.getUsersByRole(params.get("role")); + found.ifPresent(players::add); } if (params.containsKey("id")) { + ranOtherParams = true; try { Optional found = playerService.getUser(Long.parseLong(params.get("id"))); - if (found.isPresent()) - return List.of(found.get()); - else - return List.of(); - } catch (NumberFormatException e) { - return List.of(); + found.ifPresent(players::add); + } catch (NumberFormatException ignored) { } } if (params.containsKey("usernames")) { + ranOtherParams = true; String[] usernames = params.get("usernames").split(","); - List players = new ArrayList<>(); for (String username : usernames) { Optional found = playerService.getUserByUsername(username); - if (found.isPresent()) - players.add(found.get()); + found.ifPresent(players::add); } - return players; } if (params.containsKey("emails")) { + ranOtherParams = true; String[] emails = params.get("emails").split(","); - List filtered = new ArrayList<>(); for (String email : emails) { Optional found = playerService.getUserByEmail(email); - if (found.isPresent()) - filtered.add(found.get()); + found.ifPresent(players::add); } - return filtered; } - return playerService.getUsers(); + if (params.containsKey("role")) + { + if (!ranOtherParams) + return playerService.getUsersByRole(params.get("role")); + else + players.removeIf(p -> !p.getRoles().stream().anyMatch(r -> r.getName().equals(params.get("role")))); + } + + return players.stream().toList(); } + @Override public void logAccess(ApiKey apiKey, String path, Map params) { RestApiAccessLog log = new RestApiAccessLog(); @@ -101,37 +103,38 @@ public void logAccess(ApiKey apiKey, String path, Map params) { } @Override - public List getQuestions(Map params) { + public List getQuestions(Map params, Pageable pageable) { + String lang = LocaleContextHolder.getLocale().getLanguage(); + if (params.containsKey("lang")) { + lang = params.get("lang"); + } + if (params.containsKey("category")) { String category = params.get("category"); + Category cat = null; if (StringUtils.isStrictlyNumeric(category)) { - return questionService.getAllQuestions().stream() - .filter(q -> q.getCategory().getId() == Long.parseLong(category)) - .toList(); + Optional optCat = categoryService.getCategory(Long.parseLong(category)); + if (optCat.isPresent()) + cat = optCat.get(); } else { - return questionService.getAllQuestions().stream() - .filter(q -> q.getCategory().getName().equals(category)) - .toList(); + cat = categoryService.getCategoryByName(category); } + + return questionService.getQuestionsByCategory(pageable, cat, lang); } if (params.containsKey("id")) { try { Optional found = questionService.getQuestion(Long.parseLong(params.get("id"))); - if (found.isPresent()) - return List.of(found.get()); - else - return List.of(); + return found.map(List::of).orElseGet(List::of); } catch (NumberFormatException e) { return List.of(); } } if (params.containsKey("statement")) { - return questionService.getAllQuestions().stream() - .filter(q -> q.getStatement().contains(params.get("statement"))) - .toList(); + return questionService.getQuestionsByStatement(pageable, params.get("statement"), lang); } - return questionService.getAllQuestions(); + return questionService.getQuestions(pageable).toList(); } } diff --git a/src/main/java/com/uniovi/services/impl/RoleServiceImpl.java b/src/main/java/com/uniovi/services/impl/RoleServiceImpl.java index 0fae17ca..b10bbcc1 100644 --- a/src/main/java/com/uniovi/services/impl/RoleServiceImpl.java +++ b/src/main/java/com/uniovi/services/impl/RoleServiceImpl.java @@ -35,11 +35,4 @@ public Role addRole(RoleDto role) { public Role getRole(String name) { return roleRepository.findById(name).orElse(null); } - - @Override - public List getRoles() { - List roles = new ArrayList<>(); - roleRepository.findAll().forEach(roles::add); - return roles; - } } diff --git a/src/main/java/com/uniovi/validators/QuestionValidator.java b/src/main/java/com/uniovi/validators/QuestionValidator.java new file mode 100644 index 00000000..4e08e1b3 --- /dev/null +++ b/src/main/java/com/uniovi/validators/QuestionValidator.java @@ -0,0 +1,51 @@ +package com.uniovi.validators; + +import com.uniovi.dto.AnswerDto; +import com.uniovi.dto.QuestionDto; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; + +@Component +public class QuestionValidator implements Validator { + @Override + public boolean supports(Class clazz) { + return QuestionDto.class.equals(clazz); + } + + @Override + public void validate(Object target, Errors errors) { + QuestionDto question = (QuestionDto) target; + + if (question.getStatement() == null || question.getStatement().isEmpty()) { + errors.rejectValue("statement", null, + "The statement of the question cannot be empty"); + } + + if (question.getOptions() == null || question.getOptions().size() != 4) { + errors.rejectValue("options", null, + "The question must have 4 options"); + } + + if (question.getOptions().stream().anyMatch(option -> option.getText() == null || option.getText().isEmpty())) { + errors.rejectValue("options", null, + "The text of the options cannot be empty"); + } + + if (question.getOptions().stream().filter(AnswerDto::isCorrect).count() != 1) { + errors.rejectValue("options", null, + "The question must have exactly one correct option"); + } + + + if (!question.getOptions().contains(question.getCorrectAnswer())) + errors.rejectValue("correctAnswer", null, + "The correct answer must be one of the options"); + + + if (question.getCategory() == null || question.getCategory().getName() == null || question.getCategory().getName().isEmpty()) { + errors.rejectValue("category", null, + "The question must have a category"); + } + } +} diff --git a/src/main/java/com/uniovi/validators/SignUpValidator.java b/src/main/java/com/uniovi/validators/SignUpValidator.java index 07507332..24893db4 100644 --- a/src/main/java/com/uniovi/validators/SignUpValidator.java +++ b/src/main/java/com/uniovi/validators/SignUpValidator.java @@ -25,23 +25,23 @@ public void validate(Object target, Errors errors) { PlayerDto user = (PlayerDto) target; if (!EmailValidator.getInstance().isValid(user.getEmail())) { - errors.rejectValue("email", null, + errors.rejectValue("email", "signup.error.email.valid", "El email no es válido"); } if(playerService.getUserByEmail(user.getEmail()).isPresent()){ - errors.rejectValue("email", null, + errors.rejectValue("email", "signup.error.email.already", "Ya hay una cuenta registrada con este email"); } if (playerService.getUserByUsername(user.getUsername()).isPresent()) { - errors.rejectValue("username", null, + errors.rejectValue("username", "signup.error.username.already", "Ya existe una cuenta con este nombre de usuario"); } if (user.getPassword() == null || !user.getPassword().equals(user.getPasswordConfirm())) { - errors.rejectValue("passwordConfirm", null, + errors.rejectValue("passwordConfirm", "signup.error.password.match", "Las contraseñas no coinciden"); } } diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties new file mode 100644 index 00000000..600d35ad --- /dev/null +++ b/src/main/resources/application-test.properties @@ -0,0 +1,15 @@ +# Port 3000 for testing, local deployment +server.port=3000 +server.address=0.0.0.0 + +# HSQL db +spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver +spring.datasource.url=jdbc:hsqldb:hsql://localhost:9001 +spring.datasource.username=sa +spring.datasource.password= +spring.jpa.hibernate.ddl-auto=create + +springdoc.api-docs.path=/api-docs +springdoc.swagger-ui.path=/api +springdoc.swagger-ui.operationsSorter=method +springdoc.packagesToScan=com.uniovi.controllers.api \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 6785d07b..b2dc761a 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,9 +1,15 @@ # Port 3000 for testing, local deployment server.port=3000 +server.address=0.0.0.0 # HSQL db spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver spring.datasource.url=jdbc:hsqldb:hsql://localhost:9001 spring.datasource.username=sa spring.datasource.password= -spring.jpa.hibernate.ddl-auto=update \ No newline at end of file +spring.jpa.hibernate.ddl-auto=update + +springdoc.api-docs.path=/api-docs +springdoc.swagger-ui.path=/api +springdoc.swagger-ui.operationsSorter=method +springdoc.packagesToScan=com.uniovi.controllers.api diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 91f16553..2b91abb1 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -11,6 +11,8 @@ navbar.ranking.player=Tu ranking personal navbar.changeLanguage=Idioma navbar.toEnglish=Inglés navbar.toSpanish=Español +navbar.toFrench=Francés +navbar.currentLanguage=Español # Buttons for non-authenticated users navbar.signup=Regístrate @@ -51,7 +53,7 @@ login.username.placeholder=Ejemplo: wikiuser login.password.label=Contraseña: login.password.placeholder=Password_Ejemplo login.sumbit=Iniciar sesión -login.error=Error: +login.error=Error: Usuario o contraseña incorrectos login.title=Identifícate login.register=¿No tienes cuenta? Regístrate aquí @@ -66,7 +68,10 @@ signup.passwordConfirm.label=Repita la contraseña: signup.passwordConfirm.placeholder=Repita la contraseña signup.submit=Registrarse signup.title=Regístrate - +signup.error.email.valid=El correo electrónico no es válido +signup.error.email.already=El correo electrónico ya está en uso +signup.error.username.already=El nombre de usuario ya está en uso +signup.error.password.match=Las contraseñas no coinciden # -------------------Statements for the playerRanking.html and GlobalRanking.html file--------------------- ranking.title=Ranking ranking.position=Posición @@ -108,4 +113,5 @@ timeRunOut.result=¡Se acabó el tiempo! No te preocupes, sigue intentándolo. game.continue=Siguiente pregunta answer.correct=La respuesta correcta era: game.points=Puntos: +game.currentQuestion=Pregunta: game.finish=El juego ha terminado. Tu puntuación ha sido: \ No newline at end of file diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties index dac6c716..97f0f133 100644 --- a/src/main/resources/messages_en.properties +++ b/src/main/resources/messages_en.properties @@ -11,6 +11,8 @@ navbar.ranking.player=Your personal ranking navbar.changeLanguage=Language navbar.toEnglish=English navbar.toSpanish=Spanish +navbar.toFrench=French +navbar.currentLanguage=English # Buttons for non-authenticated users navbar.signup=Sign Up @@ -51,7 +53,7 @@ login.username.placeholder=Example: wikiuser login.password.label=Password: login.password.placeholder=Password_Example login.sumbit=Log in -login.error=Error: +login.error=Error: Incorrect username or password login.title=Log in login.register=Don't have an account? Sign up here @@ -66,6 +68,10 @@ signup.passwordConfirm.label=Confirm Password: signup.passwordConfirm.placeholder=Confirm your password signup.submit=Sign up signup.title=Sign up +signup.error.email.valid=Please enter a valid email address +signup.error.email.already=The email is already in use +signup.error.username.already=The username is already in use +signup.error.password.match=Passwords do not match # -------------------Statements for the playerRanking.html and GlobalRanking.html file--------------------- ranking.title=Ranking @@ -108,6 +114,7 @@ timeRunOut.result=Time's up! Don't worry, keep trying. game.continue=Next question answer.correct=Correct answer was: game.points=Points: +game.currentQuestion=Question: game.finish=The game has finished. Your score is: diff --git a/src/main/resources/messages_es.properties b/src/main/resources/messages_es.properties index b2269e1b..174dad48 100644 --- a/src/main/resources/messages_es.properties +++ b/src/main/resources/messages_es.properties @@ -11,6 +11,8 @@ navbar.ranking.player=Tu ranking personal navbar.changeLanguage=Idioma navbar.toEnglish=Inglés navbar.toSpanish=Español +navbar.toFrench=Francés +navbar.currentLanguage=Español # Buttons for non-authenticated users navbar.signup=Regístrate @@ -52,7 +54,7 @@ login.username.placeholder=Ejemplo: wikiuser login.password.label=Contraseña: login.password.placeholder=Password_Ejemplo login.sumbit=Iniciar sesión -login.error=Error: +login.error=Error: Usuario o contraseña incorrectos login.title=Identifícate login.register=¿No tienes cuenta? Regístrate aquí @@ -67,6 +69,10 @@ signup.passwordConfirm.label=Repita la contraseña: signup.passwordConfirm.placeholder=Repita la contraseña signup.submit=Registrarse signup.title=Regístrate +signup.error.email.valid=El correo electrónico no es válido +signup.error.email.already=El correo electrónico ya está en uso +signup.error.username.already=El nombre de usuario ya está en uso +signup.error.password.match=Las contraseñas no coinciden # -------------------Statements for the playerRanking.html and GlobalRanking.html file--------------------- ranking.title=Ranking @@ -109,4 +115,5 @@ timeRunOut.result=¡Se acabó el tiempo! No te preocupes, sigue intentándolo. game.continue=Siguiente pregunta answer.correct=La respuesta correcta era: game.points=Puntos: +game.currentQuestion=Pregunta: game.finish=El juego ha terminado. Tu puntuación ha sido: \ No newline at end of file diff --git a/src/main/resources/messages_fr.properties b/src/main/resources/messages_fr.properties new file mode 100644 index 00000000..1f5d2b22 --- /dev/null +++ b/src/main/resources/messages_fr.properties @@ -0,0 +1,114 @@ +# -------------------Statements for the nav.html file---------------------- +navbar.home=Accueil +navbar.play=Jouer +navbar.game1=Jeu 1 +navbar.game2=Jeu 2 +navbar.history=Historique +navbar.ranking=Classement +navbar.ranking.global=Classement mondial +navbar.ranking.player=Votre classement personnel +navbar.changeLanguage=Langue +navbar.toEnglish=Anglais +navbar.toSpanish=Espagnol +navbar.toFrench=Français +navbar.currentLanguage=Français + +navbar.signup=S'inscrire +navbar.login=Se connecter +navbar.profile.apikey=Clé d'API + +# Buttons for authenticated users +navbar.profile=Profil +navbar.logout=Se déconnecter + + +# -------------------Statements for the footer.html file--------------------- +footer.copyright=© ASW - Groupe 04 B +footer.nav=Menu de navigation + +# -------------------Statements for the error.html file--------------------- +error.page.title=Erreur ! +error.status=Statut : +error.message=Message d'erreur : +error.error=Erreur : + +# -------------------Statements for the index.html file--------------------- +index.heading=WIQ +index.subtitle=Répondez aux questions correctement et GAGNEZ !!! +index.button=JOUER + +# -------------------Statements for the home.html file--------------------- +home.heading=Bienvenue +home.private_zone=Ceci est une zone privée du site +home.authenticated_as=Utilisateur authentifié en tant que : +home.apikey.title=Clé d'API +home.apikey.description=Ceci est votre clé d'API. Utilisez-la pour accéder aux ressources de l'API de WIQ. +home.apikey.missing=Vous n'avez pas de clé d'API. Obtenez-la en cliquant sur ce bouton. +home.apikey.create=Obtenir une clé + +# -------------------Statements for the login.html file--------------------- +login.username.label=Nom d'utilisateur : +login.username.placeholder=Exemple : utilisateurwiki +login.password.label=Mot de passe : +login.password.placeholder=Motdepasse_Exemple +login.submit=Se connecter +login.error=Erreur : Nom d'utilisateur ou mot de passe incorrect +login.title=Identifiez-vous +login.register=Pas encore de compte ? Inscrivez-vous ici + +# -------------------Statements for the signup.html file--------------------- +signup.username.label=Nom d'utilisateur : +signup.username.placeholder=utilisateurwiki +signup.email.label=Adresse e-mail : +signup.email.placeholder=test@test.com +signup.password.label=Mot de passe : +signup.password.placeholder=Entrez le mot de passe +signup.passwordConfirm.label=Confirmer le mot de passe : +signup.passwordConfirm.placeholder=Confirmez le mot de passe +signup.submit=S'inscrire +signup.title=Inscrivez-vous + +# -------------------Statements for the playerRanking.html and GlobalRanking.html file--------------------- +ranking.title=Classement +ranking.position=Position +ranking.score=Score +ranking.date=Date +ranking.player=Joueur +ranking.question.right=Réponses correctes +ranking.question.wrong=Réponses incorrectes +ranking.time=Temps + +# -------------------Statements for the apiHome.html file--------------------- +api.doc.title=Documentation de l'API +api.doc.description=Ceci est la documentation de l'API de WIQ. Vous pouvez trouver ici des informations sur les ressources disponibles, les paramètres qu'elles acceptent et des exemples d'utilisation. +api.doc.table.parameters=Paramètres +api.doc.table.description=Description +api.doc.table.example=Exemple +api.doc.endpoints.players.title=Point de terminaison /api/players +api.doc.endpoints.players.description=Renvoie une liste de joueurs filtrée selon les critères spécifiés. +api.doc.endpoints.questions.title=Point de terminaison /api/questions +api.doc.endpoints.questions.description=Renvoie une liste de questions filtrée selon les critères spécifiés. +api.doc.exampleRequest=Exemple de requête +api.doc.exampleResponse=Exemple de réponse +api.doc.apikey=Clé d'API (obligatoire) + +api.doc.player.username=Nom d'utilisateur (optionnel) +api.doc.player.email=Adresse e-mail (optionnel) +api.doc.player.id=Identifiant du joueur dans le système (optionnel) +api.doc.player.usernames=Noms d'utilisateur, séparés par des virgules (optionnel) +api.doc.player.emails=Adresses e-mail, séparées par des virgules (optionnel) + +api.doc.question.category=Catégorie (optionnel). Nom ou ID de la catégorie. +api.doc.question.id=ID de la question (optionnel) +api.doc.question.statement=Énoncé de la question (optionnel). Texte que l'énoncé de la question doit contenir. + +# -------------------Statements for the game fragments--------------------- +correctAnswer.result=Réponse correcte, continuez comme ça ! +failedAnswer.result=Réponse incorrecte, ne vous découragez pas et continuez à essayer. +timeRunOut.result=Temps écoulé ! Ne vous inquiétez pas, continuez à essayer. +game.continue=Question suivante +answer.correct=La réponse correcte était : +game.points=Points: +game.currentQuestion=Question: +game.finish=Le jeu est terminé. Votre score est : + diff --git a/src/main/resources/static/css/custom.css b/src/main/resources/static/css/custom.css index 0998067f..37ab4183 100644 --- a/src/main/resources/static/css/custom.css +++ b/src/main/resources/static/css/custom.css @@ -23,13 +23,13 @@ footer { /* Estilo personalizado para el botón */ -.btn-custom, .page-link { +.btn-custom, .btn-primary, .page-link { color: #fff; background-color: transparent; border: 2px solid #fff; } -.btn-custom:hover, .page-link:hover { +.btn-custom:hover, .btn-primary:hover, .page-link:hover { background-color: #fff; color: #000; } @@ -42,3 +42,24 @@ footer { .table-hover tbody tr:hover td { background: white; } + +.col-md-12 .display-4 { + font-size: 10em; +} + +.col-md-12 .lead, .col-md-12 .btn { + font-size: 1.75em; +} + + +.nav { + background-color: transparent !important; +} + +.nav .nav-link { + color: white !important; /* Cambia el color del texto del enlace a blanco */ +} + +.nav .nav-link:hover { + color: rgba(255, 255, 255, 0.7) !important; /* Cambia el color del texto del enlace cuando se pasa el mouse */ +} \ No newline at end of file diff --git a/src/main/resources/static/css/game.css b/src/main/resources/static/css/game.css index 263cec64..1f116d49 100644 --- a/src/main/resources/static/css/game.css +++ b/src/main/resources/static/css/game.css @@ -2,7 +2,7 @@ position: relative; text-align: center; width: 35%; - margin: auto; + margin: 2% auto; } .countdown { @@ -11,7 +11,7 @@ left: 50%; transform: translate(-50%, -50%); font-size: 2em; - color: black; + color: white; } .stopwatch-img { width: 45%; @@ -19,8 +19,8 @@ } .game-logo { - margin: 0 0 5% 0; - width: 25%; + margin: auto; + width: 15%; height: auto; } @@ -28,7 +28,7 @@ margin-bottom: 10%; } -.points { +.points, .questionCounter { font-size: 2em; color: white; } @@ -45,4 +45,15 @@ .countdown { font-size: 3em; } +} + +.container .btn { + color: #fff; + background-color: transparent; + border: 2px solid #fff; +} + +.container .btn:hover { + background-color: #fff; + color: #000; } \ No newline at end of file diff --git a/src/main/resources/static/images/if_spain_flag.png b/src/main/resources/static/images/if_spain_flag.png deleted file mode 100644 index 36b30d75..00000000 Binary files a/src/main/resources/static/images/if_spain_flag.png and /dev/null differ diff --git a/src/main/resources/static/images/if_uk_flag.png b/src/main/resources/static/images/if_uk_flag.png deleted file mode 100644 index 0291e298..00000000 Binary files a/src/main/resources/static/images/if_uk_flag.png and /dev/null differ diff --git a/src/main/resources/static/images/logo_correct.svg b/src/main/resources/static/images/logo_correct.svg new file mode 100644 index 00000000..a877ba75 --- /dev/null +++ b/src/main/resources/static/images/logo_correct.svg @@ -0,0 +1,102 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/static/images/logo_incorrect.svg b/src/main/resources/static/images/logo_incorrect.svg new file mode 100644 index 00000000..5cd82a6a --- /dev/null +++ b/src/main/resources/static/images/logo_incorrect.svg @@ -0,0 +1,103 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/static/images/stopwatch.svg b/src/main/resources/static/images/stopwatch.svg new file mode 100644 index 00000000..7870a0c4 --- /dev/null +++ b/src/main/resources/static/images/stopwatch.svg @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/fragments/nav.html b/src/main/resources/templates/fragments/nav.html index 62f2b7cb..d65cdd78 100644 --- a/src/main/resources/templates/fragments/nav.html +++ b/src/main/resources/templates/fragments/nav.html @@ -35,19 +35,21 @@ diff --git a/src/main/resources/templates/game/basicGame.html b/src/main/resources/templates/game/basicGame.html index c53e5148..43c37fad 100644 --- a/src/main/resources/templates/game/basicGame.html +++ b/src/main/resources/templates/game/basicGame.html @@ -9,6 +9,14 @@

+

+ + + + / + + +

diff --git a/src/main/resources/templates/game/fragments/gameFinished.html b/src/main/resources/templates/game/fragments/gameFinished.html index ee10d9e6..dd264b15 100644 --- a/src/main/resources/templates/game/fragments/gameFinished.html +++ b/src/main/resources/templates/game/fragments/gameFinished.html @@ -16,6 +16,7 @@

\ No newline at end of file diff --git a/src/main/resources/templates/game/fragments/questionResult.html b/src/main/resources/templates/game/fragments/questionResult.html index 1db7fe88..f8b2ab13 100644 --- a/src/main/resources/templates/game/fragments/questionResult.html +++ b/src/main/resources/templates/game/fragments/questionResult.html @@ -19,6 +19,7 @@

let activeTimeout = setTimeout(function () { clearInterval(interval); // Ensure the interval is cleared when the timeout completes $("#gameFrame").load('/game/update'); + updateQuestionCounter(); }, timeoutPeriod); timeoutPeriod = timeoutPeriod - updateInterval * 2; // Adjust the timeout period to account for the update interval @@ -43,12 +44,24 @@

} } + function updateQuestionCounter() { + $.ajax({ + type: "GET", + url: "/game/currentQuestion", + success: function (response) { + if (!isNaN(response)) + $("#currentQuestion").text(response); + } + }); + } + $("#continueBtn").off('click').on('click', function () { if (activeTimeout) { clearTimeout(activeTimeout); clearInterval(interval); } $("#gameFrame").load("/game/update"); + updateQuestionCounter(); }); } diff --git a/src/main/resources/templates/game/fragments/stopwatch.html b/src/main/resources/templates/game/fragments/stopwatch.html index b0ced56c..1282f055 100644 --- a/src/main/resources/templates/game/fragments/stopwatch.html +++ b/src/main/resources/templates/game/fragments/stopwatch.html @@ -1,6 +1,6 @@
- Stopwatch + Stopwatch
diff --git a/src/main/resources/templates/player/login.html b/src/main/resources/templates/player/login.html index baf00d09..5e73a04f 100644 --- a/src/main/resources/templates/player/login.html +++ b/src/main/resources/templates/player/login.html @@ -7,7 +7,11 @@
- + +

@@ -33,7 +37,9 @@

- +