diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5ad5f1304f0a6d15e935c7ad4378f55366673891..e9b2b144f896c631cfb1129ec249c0bd35b386c1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,10 +1,10 @@ # -# ** header v3.0 # This file is a part of the CaosDB Project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen # Copyright (C) 2019 Henrik tom Wörden +# Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -19,11 +19,9 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. # -# ** end header -# variables: - DEPLOY_REF: f-grpc + DEPLOY_REF: dev CI_REGISTRY_IMAGE: $CI_REGISTRY/caosdb/src/caosdb-server/caosdb-server-testenv:latest GIT_SUBMODULE_STRATEGY: normal @@ -41,18 +39,25 @@ stages: - test - deploy +.env: &env + - F_BRANCH="${CI_COMMIT_REF_NAME}" + info: tags: [cached-dind] image: docker:20.10 stage: info needs: [] script: + - *env - echo "Pipeline triggered by $TRIGGERED_BY_REPO@$TRIGGERED_BY_REF ($TRIGGERED_BY_HASH)" + - echo "Pipeline will trigger DEPLOY with branch $DEPLOY_REF" + - echo "F_BRANCH = $F_BRANCH" + # Setup: Build a docker image in which tests for this repository can run build-testenv: tags: [ cached-dind ] - image: docker:19.03 + image: docker:20.10 stage: setup timeout: 3h only: @@ -78,26 +83,14 @@ test: - mvn compile - mvn test + + # Deploy: Trigger building of server image and integration tests trigger_build: tags: [ docker ] stage: deploy script: - - F_BRANCH="${CI_COMMIT_REF_NAME}" - - # TODO remove, this is grpc-special stuff - # server in f-grpc-dev branch matches with dev branch of cpplib/cppinttest - - if echo "$F_BRANCH" | grep -c "^f-grpc-dev$"; then - F_BRANCH=dev; - fi - # server in f-grpc-main branch matches with main branch of cpplib/cppinttest - - if echo "$F_BRANCH" | grep -c "^f-grpc-main$"; then - F_BRANCH=main; - fi - # server in f-grpc-f-something branch matches with f-something branch of cpplib/cppinttest - - if echo "$F_BRANCH" | grep -c "^f-grpc-f-.*$"; then - F_BRANCH=`echo "${F_BRANCH:7}"`; - fi + - *env - echo "Triggering pipeline ${DEPLOY_PIPELINE}@${DEPLOY_REF} with F_BRANCH=${F_BRANCH}" - /usr/bin/curl -X POST diff --git a/CHANGELOG.md b/CHANGELOG.md index cbdc98008960ef2fdce6402e404d52469cbead41..ca41b8287dba890cdeadabcf4886aa3f3308bfd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,34 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [v0.6.0] - 2021-11-17 +(Timm Fitschen) ### Added +* Endpoint for CaosDB GRPC API 0.1 (see https://gitlab.com/caosdb-proto.git for + more). + Authentication is supported via a Basic scheme, using the well-known + "authentication" header. + Notable limitations of the current implementation of the API: + * It is currently not possible to mix retrievals + (caosdb.entity.v1.RetrieveRequest) with any other transaction type - so + transaction are either read-only or write-only. The server throws an error + if it finds mixed read/write transactions. + * It is currently not possible to have more that one query + (caosdb.entity.v1.Query) in a single transaction. The server throws an + error if it finds more than one query. + + ### Changed ### Deprecated +* Legacy XML/HTTP API (also known as the REST API). The API will not be removed + until the web interface (caosdb-webui) and the python client libraries have + been updated and freed from any dependencies. However, new clients should not + implement this API anymore. + ### Removed ### Fixed @@ -24,7 +44,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added * An openAPI specification of the XML api -* New server configuration option `SERVER_BIND_ADDRESS`, which is the address to listen to. See [server.conf](conf/core/server.conf). +* New server configuration option `SERVER_BIND_ADDRESS`, which is the address to listen to. See + [server.conf](conf/core/server.conf). ### Changed diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 6159dcd8f0ed2296e2f3ac992830f03659d1a131..2f2967d0e835abc882650356ab2cf0c29bd9db47 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -1,5 +1,30 @@ -* caosdb-mysqlbackend == 5.0.0 -* Java 11 -* Apache Maven >= 3.6.0 -* make >= 4.2.0 +# Dependencies + +## For Building and Running the Server + +* `>=caosdb-proto 0.1.0` +* `>=caosdb-mysqlbackend 5.0.0` +* `>=Java 11` +* `>=Apache Maven 3.6.0` +* `>=Make 4.2` +* `libpam` (if PAM authentication is required) * More dependencies are being pulled and installed automatically by Maven. See the complete list of dependencies in the [pom.xml](pom.xml) + +## For Deploying a Web User Interface (optional) + +* `>=caosdb-webui 0.4.` + +## For Building the Documentation (optional) + +* `>=Python 3.8` +* `>=pip 21.0.0` + +## For Server-side Scripting (optional) + +* `>=Python 3.8` +* `>=pip 21.0.0` +* `openpyxl` (for XLS/ODS export) + +## Recommended Packages + +* `openssl` (if a custom TLS certificate is required) diff --git a/FEATURES.md b/FEATURES.md new file mode 100644 index 0000000000000000000000000000000000000000..a5341f355fb67d0ca05e82642840789aac43bb45 --- /dev/null +++ b/FEATURES.md @@ -0,0 +1,21 @@ +# Features + +* The CaosDB Server implements a CaosDB GRPC API Endpoint (v0.1.0) + Authentication is supported via a Basic scheme, using the well-known + "authentication" header. + Notable limitations of the current implementation of the API: + * It is currently not possible to mix retrievals + (caosdb.entity.v1.RetrieveRequest) with any other transaction type - so + transaction are either read-only or write-only. The server throws an error + if it finds mixed read/write transactions. + * It is currently not possible to have more that one query + (caosdb.entity.v1.Query) in a single transaction. The server throws an + error if it finds more than one query. +* Legacy XML/HTTP API (Deprecated) +* Deployment of caosdb-webui (>=v0.4.1) +* Server-side Scripting API (v0.1) +* CaosDB Query Language Processor +* CaosDB FileSystem +* User Management, Authentication and Authorization + * Internal authentication service + * Authentication via an external service. diff --git a/README_SETUP.md b/README_SETUP.md index d738ad13768df8878b55808e4519202fc95dbd86..5065e3383c4ac2f2d549bfedb15687d0b4124ec0 100644 --- a/README_SETUP.md +++ b/README_SETUP.md @@ -5,26 +5,7 @@ more. ## Requirements -### CaosDB Packages - -* caosdb-webui=0.2.1 -* caosdb-mysqlbackend=3.0 - -### Third-party Software - -* `>=Java 8` -* `>=Apache Maven 3.0.4` -* `>=Python 3.4` -* `>=pip 9.0.1` -* `>=git 1.9.1` -* `>=Make 3.81` -* `>=Screen 4.01` -* `>=MySQL 5.5` (better `>=5.6`) or `>=MariaDB 10.1` -* `libpam` (if PAM authentication is required) -* `unzip` -* `openpyxl` (for XLS/ODS export) -* `openssl` (if a custom TLS certificate is required) -- `easy-units` >= 0.0.1 https://gitlab.com/timm.fitschen/easy-units +See [DEPENDENCIES.md](DEPENDENCIES.md). #### Install the requirements on Debian diff --git a/RELEASE_GUIDELINES.md b/RELEASE_GUIDELINES.md index 5c1fd68d462212e9b81dbc803fc590006df36a3d..4b9185323d3b6fdafbd049e7c68273c909de5a05 100644 --- a/RELEASE_GUIDELINES.md +++ b/RELEASE_GUIDELINES.md @@ -31,3 +31,5 @@ guidelines of the CaosDB Project 8. Update the version property in [pom.xml](./pom.xml) for the next developlement round (with a `-SNAPSHOT` suffix). + +9. Add a gitlab release in the respective repository. diff --git a/caosdb-proto b/caosdb-proto index 0aa6278dbdf5a18e1909050eedf8b2134b194810..4e0552f3bd0e40c96ec534f605f38ed7650bcdf1 160000 --- a/caosdb-proto +++ b/caosdb-proto @@ -1 +1 @@ -Subproject commit 0aa6278dbdf5a18e1909050eedf8b2134b194810 +Subproject commit 4e0552f3bd0e40c96ec534f605f38ed7650bcdf1 diff --git a/caosdb-webui b/caosdb-webui index 8e5799db53b853b06a51a3bd250daeb9c779eee5..ed062d621ba1b8c7c05308fe8870d8dfee4c9b1f 160000 --- a/caosdb-webui +++ b/caosdb-webui @@ -1 +1 @@ -Subproject commit 8e5799db53b853b06a51a3bd250daeb9c779eee5 +Subproject commit ed062d621ba1b8c7c05308fe8870d8dfee4c9b1f diff --git a/pom.xml b/pom.xml index 691c82fb89d727680741201641f18c47e2fb52d6..2837e6bb37494344fa9221c0393131b907bc60d1 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.caosdb</groupId> <artifactId>caosdb-server</artifactId> - <version>0.5.1-GRPC0.1.1</version> + <version>0.6.1-SNAPSHOT</version> <packaging>jar</packaging> <name>CaosDB Server</name> <scm> diff --git a/src/doc/DEPENDENCIES.md b/src/doc/DEPENDENCIES.md new file mode 120000 index 0000000000000000000000000000000000000000..28771e4dc45403b9c9baa795f04584e5b0a283ec --- /dev/null +++ b/src/doc/DEPENDENCIES.md @@ -0,0 +1 @@ +../../DEPENDENCIES.md \ No newline at end of file diff --git a/src/doc/conf.py b/src/doc/conf.py index 4e5ff81b4175032fa9bfeb759d8258621cec4be2..3e4e90e8c26fcc1fc709f20b82d06d21d2b5f787 100644 --- a/src/doc/conf.py +++ b/src/doc/conf.py @@ -25,9 +25,9 @@ copyright = '2020, IndiScale GmbH' author = 'Daniel Hornung' # The short X.Y version -version = '0.5.1' +version = '0.6' # The full version, including alpha/beta/rc tags -release = '0.5.1-GRPC0.1.0' +release = '0.6.0' # -- General configuration --------------------------------------------------- diff --git a/src/doc/index.rst b/src/doc/index.rst index 21fd891c083e7932d8b342d93992b2d02158364e..67a9e365f506009da21b3a6c00b771e751bf26c0 100644 --- a/src/doc/index.rst +++ b/src/doc/index.rst @@ -13,6 +13,7 @@ Welcome to caosdb-server's documentation! Query Language <CaosDB-Query-Language> administration Development <development/devel> + Dependencies <DEPENDENCIES> specification/index.rst Glossary API documentation<_apidoc/packages> diff --git a/src/main/java/org/caosdb/server/FileSystem.java b/src/main/java/org/caosdb/server/FileSystem.java index 6bff612ca69acc24b699f8807b6969e343c60fb3..67587f3da7930dd2cbf3e76d3ed06f19508efef7 100644 --- a/src/main/java/org/caosdb/server/FileSystem.java +++ b/src/main/java/org/caosdb/server/FileSystem.java @@ -174,7 +174,7 @@ public class FileSystem { tmpFile.getParentFile().mkdirs(); if (tmpFile.isDirectory()) { // TODO this should generate an error. This means that the - // tmpIdentifyers are inconsistent + // tmpIdentifiers are inconsistent } final OutputStream outputStream = new FileOutputStream(tmpFile); final MessageDigest md = MessageDigest.getInstance("SHA-512"); diff --git a/src/main/java/org/caosdb/server/datatype/CaosEnum.java b/src/main/java/org/caosdb/server/datatype/CaosEnum.java index 1040ab9a8114544dfd8a0d5a0a75660be4de5f07..00d8cb167a158a40417e7fddcb9fbe1cf21e7cdb 100644 --- a/src/main/java/org/caosdb/server/datatype/CaosEnum.java +++ b/src/main/java/org/caosdb/server/datatype/CaosEnum.java @@ -61,17 +61,17 @@ class EnumElement implements Comparable<EnumElement> { public class CaosEnum { - final boolean cs; + final boolean case_sensitive; // for string operations public CaosEnum(final String... values) { this(false, values); } - public CaosEnum(final boolean cs, final String... values) { - this.cs = cs; + public CaosEnum(final boolean case_sensitive, final String... values) { + this.case_sensitive = case_sensitive; int index = 0; for (String v : values) { - if (!cs) { + if (!case_sensitive) { v = v.toUpperCase(); } this.values.add(new EnumElement(index++, v)); @@ -82,7 +82,7 @@ public class CaosEnum { public EnumElement valueOf(final String s) { int hash; - if (!this.cs) { + if (!this.case_sensitive) { hash = s.toUpperCase().hashCode(); } else { hash = s.hashCode(); diff --git a/src/main/java/org/caosdb/server/entity/Entity.java b/src/main/java/org/caosdb/server/entity/Entity.java index 76ed7bf1ed2a16dfbade6d6effb162e391ce1c84..20ef481cde3845a35fbdc3853fb12a31278dc7e3 100644 --- a/src/main/java/org/caosdb/server/entity/Entity.java +++ b/src/main/java/org/caosdb/server/entity/Entity.java @@ -550,79 +550,11 @@ public class Entity extends AbstractObservable implements EntityInterface { getToElementStrategy().addToElement(this, element, strategy); } - /** - * Print this entity to the standard outputs. Just for debugging. - * - * @throws CaosDBException - */ - @Override - public void print() { - print(""); - } - @Override public Integer getDomain() { return 0; } - @Override - public void print(final String indent) { - System.out.println( - indent - + "+---| " - + this.getClass().getSimpleName() - + " |----------------------------------"); - if (getDomain() != 0) { - System.out.println(indent + "| Domain: " + Integer.toString(getDomain())); - } - if (hasId()) { - System.out.println(indent + "| ID: " + Integer.toString(getId())); - } - if (hasCuid()) { - System.out.println(indent + "| Cuid: " + getCuid()); - } - if (hasName()) { - System.out.println(indent + "| Name: " + getName()); - } - if (hasDescription()) { - System.out.println(indent + "| Description: " + getDescription()); - } - if (hasRole()) { - System.out.println(indent + "| Role: " + getRole()); - } - if (hasStatementStatus()) { - System.out.println(indent + "| Statement: " + getStatementStatus().toString()); - } - if (hasDatatype()) { - System.out.println(indent + "| Datatype: " + getDatatype().toString()); - } - if (hasValue()) { - System.out.println(indent + "| Value: " + getValue().toString()); - } - if (hasEntityStatus()) { - System.out.println(indent + "| Entity: " + getEntityStatus().toString()); - } - if (hasFileProperties()) { - getFileProperties().print(indent); - } - System.out.println(indent + "+-----------------------------------"); - for (final ToElementable m : getMessages()) { - if (m instanceof Message) { - ((Message) m).print(indent + "| "); - } - } - for (final EntityInterface p : getParents()) { - // p.print(indent + "| "); - System.out.println(indent + "| Parent: " + p.getName()); - } - for (final EntityInterface s : getProperties()) { - s.print(indent + "| "); - } - if (indent.equals("")) { - System.out.println(indent + "+------------------------------------"); - } - } - /** Errors, Warnings and Info messages for this entity. */ private final Set<ToElementable> messages = new HashSet<>(); @@ -700,7 +632,6 @@ public class Entity extends AbstractObservable implements EntityInterface { if (!this.isParsed) { this.isParsed = true; setValue(getDatatype().parseValue(getValue())); - this.isParsed = true; } } @@ -874,23 +805,23 @@ public class Entity extends AbstractObservable implements EntityInterface { } // Parse TMPIDENTIFYER. - String tmpIdentifyer = null; + String tmpIdentifier = null; boolean pickup = false; if (element.getAttribute("pickup") != null && !element.getAttributeValue("pickup").equals("")) { - tmpIdentifyer = element.getAttributeValue("pickup"); + tmpIdentifier = element.getAttributeValue("pickup"); pickup = true; } else if (element.getAttribute("upload") != null && !element.getAttributeValue("upload").equals("")) { - tmpIdentifyer = element.getAttributeValue("upload"); + tmpIdentifier = element.getAttributeValue("upload"); } - if (tmpIdentifyer != null && tmpIdentifyer.endsWith("/")) { - tmpIdentifyer = tmpIdentifyer.substring(0, tmpIdentifyer.length() - 1); + if (tmpIdentifier != null && tmpIdentifier.endsWith("/")) { + tmpIdentifier = tmpIdentifier.substring(0, tmpIdentifier.length() - 1); } // Store PATH, HASH, SIZE, TMPIDENTIFYER - if (tmpIdentifyer != null || checksum != null || path != null || size != null) { + if (tmpIdentifier != null || checksum != null || path != null || size != null) { setFileProperties( - new FileProperties(checksum, path, size, tmpIdentifyer).setPickupable(pickup)); + new FileProperties(checksum, path, size, tmpIdentifier).setPickupable(pickup)); } // Parse flags diff --git a/src/main/java/org/caosdb/server/entity/EntityInterface.java b/src/main/java/org/caosdb/server/entity/EntityInterface.java index 954bcc47ca5b6117d3164ba3c9c585dbd373d4f8..46726df63dcedb651e0762f54a7b2cdafb5041d7 100644 --- a/src/main/java/org/caosdb/server/entity/EntityInterface.java +++ b/src/main/java/org/caosdb/server/entity/EntityInterface.java @@ -112,10 +112,6 @@ public interface EntityInterface public abstract boolean hasDatatype(); - public abstract void print(); - - public abstract void print(String indent); - public abstract FileProperties getFileProperties(); public abstract void setFileProperties(FileProperties fileProperties); diff --git a/src/main/java/org/caosdb/server/entity/FileProperties.java b/src/main/java/org/caosdb/server/entity/FileProperties.java index c2c2c10fae44d4d84af56a33a052f5ed589debed..eaf4246f6c16a0f7cb38964e0ffb12757a4f0373 100644 --- a/src/main/java/org/caosdb/server/entity/FileProperties.java +++ b/src/main/java/org/caosdb/server/entity/FileProperties.java @@ -38,7 +38,7 @@ public class FileProperties { private String checksum = null; private String path = null; private Long size = null; - private String tmpIdentifyer = null; + private String tmpIdentifier = null; public FileProperties setChecksum(final String checksum) { this.checksum = checksum; @@ -96,26 +96,11 @@ public class FileProperties { } public FileProperties( - final String checksum, final String path, final Long size, final String tmpIdentifyer) { + final String checksum, final String path, final Long size, final String tmpIdentifier) { this.checksum = checksum; this.path = (path == null ? null : path.replaceFirst("^/", "")); this.size = size; - this.tmpIdentifyer = tmpIdentifyer; - } - - public void print(final String indent) { - if (hasChecksum()) { - System.out.println(indent + "| Checksum: " + this.checksum); - } - if (hasPath()) { - System.out.println(indent + "| Path: " + "/" + this.path); - } - if (hasSize()) { - System.out.println(indent + "| Size: " + Long.toString(this.size)); - } - if (getFile() != null) { - System.out.println(indent + "| File: " + getFile().getAbsolutePath()); - } + this.tmpIdentifier = tmpIdentifier; } public FileProperties setFile(final File file) { @@ -127,13 +112,13 @@ public class FileProperties { return this.file; } - public FileProperties setTmpIdentifyer(final String tmpIdentifyer) { - this.tmpIdentifyer = tmpIdentifyer; + public FileProperties setTmpIdentifier(final String tmpIdentifier) { + this.tmpIdentifier = tmpIdentifier; return this; } - public String getTmpIdentifyer() { - return this.tmpIdentifyer; + public String getTmpIdentifier() { + return this.tmpIdentifier; } private String getThumbnailPath(final File target) { @@ -291,6 +276,6 @@ public class FileProperties { } public boolean hasTmpIdentifier() { - return this.tmpIdentifyer != null; + return this.tmpIdentifier != null; } } diff --git a/src/main/java/org/caosdb/server/entity/Message.java b/src/main/java/org/caosdb/server/entity/Message.java index 7f5c283640470480f552e1d9d61867911d439180..4c89e1ee23839483f7bed1099c52e8c24a56a6a2 100644 --- a/src/main/java/org/caosdb/server/entity/Message.java +++ b/src/main/java/org/caosdb/server/entity/Message.java @@ -182,23 +182,6 @@ public class Message extends Exception implements Comparable<Message>, ToElement parent.addContent(e); } - /** Print this entity to the standard outputs. Just for debugging. */ - public final void print() { - print(""); - } - - public final void print(final String indent) { - System.out.println(indent + "+---| " + this.type + " |------------------------ "); - System.out.println(indent + "| Code: " + this.code.toString()); - System.out.println(indent + "| Description: " + this.description); - System.out.println(indent + "| Body: " + this.body); - System.out.println(indent + "+------------------------------------------------------ "); - } - - public boolean equalsCore(final Message other) { - return this.code == other.code && this.description == other.description; - } - @Override public int compareTo(final Message o) { final int tc = this.type.compareToIgnoreCase(o.type); diff --git a/src/main/java/org/caosdb/server/entity/container/TransactionContainer.java b/src/main/java/org/caosdb/server/entity/container/TransactionContainer.java index 18a7837df27b39efa92abb2b16943a3476dca9ec..7e9a2ba36bc1fe7474e8dc57a9fe3e2d5e649c6f 100644 --- a/src/main/java/org/caosdb/server/entity/container/TransactionContainer.java +++ b/src/main/java/org/caosdb/server/entity/container/TransactionContainer.java @@ -114,15 +114,6 @@ public class TransactionContainer extends Container<EntityInterface> } } - public void print() { - System.out.println("*******************************************************************"); - System.out.println("*******************************************************************"); - for (final EntityInterface e : this) { - e.print("*"); - } - System.out.println("*******************************************************************\n\n"); - } - /** The files that have been uploaded. */ private HashMap<String, FileProperties> files = new HashMap<String, FileProperties>(); diff --git a/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java b/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java index 140bb207b61d6f50a593feb24a43b3e324ddcff7..e5115dc219ac427e93ae87c0921ced965023f55e 100644 --- a/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java +++ b/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java @@ -290,16 +290,6 @@ public class EntityWrapper implements EntityInterface { this.entity.addToElement(element); } - @Override - public void print() { - this.entity.print(); - } - - @Override - public void print(final String indent) { - this.entity.print(indent); - } - @Override public FileProperties getFileProperties() { return this.entity.getFileProperties(); diff --git a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java index a9c74cc1bed1cdd0de26847e629d1264db377753..7062defe36121177976d43bc58355f87f235ff8a 100644 --- a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java +++ b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java @@ -45,7 +45,8 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa } /** - * Handle read-only transactions. + * Handle read-only transactions. Of these only one may be a query at the moment, the others must + * be ID retrieves. * * @param request * @return @@ -56,7 +57,7 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa final RetrieveContainer container = new RetrieveContainer( SecurityUtils.getSubject(), getTimestamp(), getSRID(), new HashMap<>()); - FileDownload file_download = null; + FileDownload fileDownload = null; for (final TransactionRequest sub_request : request.getRequestsList()) { if (sub_request.getWrappedRequestsCase() != WrappedRequestsCase.RETRIEVE_REQUEST) { @@ -65,20 +66,23 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa + sub_request.getWrappedRequestsCase().name() + " in a read-only request."); } - final boolean fileDownload = sub_request.getRetrieveRequest().getRegisterFileDownload(); - if (sub_request.getRetrieveRequest().hasQuery() + final boolean isFileDownload = sub_request.getRetrieveRequest().getRegisterFileDownload(); + if (sub_request.getRetrieveRequest().hasQuery() // Retrieves are either queries... && !sub_request.getRetrieveRequest().getQuery().getQuery().isBlank()) { final String query = sub_request.getRetrieveRequest().getQuery().getQuery(); + if (container.getFlags().containsKey("query")) { // Check for more than one query request. + throw new CaosDBException("Cannot process more than one query request."); + } container.getFlags().put("query", query); - if (fileDownload) { + if (isFileDownload) { container.getFlags().put("download_files", "true"); } - } else { + } else { // or ID retrieves. final String id = sub_request.getRetrieveRequest().getId(); if (!id.isBlank()) { try { final RetrieveEntity entity = new RetrieveEntity(grpcToCaosdb.getId(id)); - if (fileDownload) { + if (isFileDownload) { entity.setFlag("download_files", "true"); } container.add(entity); @@ -102,13 +106,13 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa final EntityResponse.Builder entityResponse = caosdbToGrpc.convert(entity); if ((download_files_container || entity.getFlags().containsKey("download_files")) && entity.hasFileProperties()) { - if (file_download == null) { - file_download = fileTransmissionService.registerFileDownload(null); + if (fileDownload == null) { + fileDownload = fileTransmissionService.registerFileDownload(null); } entity.getFileProperties().retrieveFromFileSystem(); entityResponse.setDownloadId( fileTransmissionService.registerFileDownload( - file_download.getId(), entity.getFileProperties())); + fileDownload.getId(), entity.getFileProperties())); } builder .addResponsesBuilder() @@ -116,16 +120,15 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa } } - // Add those entities which have not been retrieved because the have a string id + // Add those entities which have not been retrieved because they have a string id for (final TransactionRequest sub_request : request.getRequestsList()) { final String id = sub_request.getRetrieveRequest().getId(); if (!id.isBlank()) { try { grpcToCaosdb.getId(id); } catch (final NumberFormatException e) { - // ID wasn't an integer - the server doesn't support string id's yet, so that entity - // cannot - // exist. + // ID wasn't an integer - the server doesn't support string ids yet, so that entity + // cannot exist. builder.addResponses( TransactionResponse.newBuilder() .setRetrieveResponse( @@ -154,6 +157,8 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa /** * Handle all entity transactions. * + * <p>Currently either all requests must be read-only/retrieve requests, or none of the requests. + * * @param request * @return * @throws Exception @@ -161,8 +166,9 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa public MultiTransactionResponse transaction(final MultiTransactionRequest request) throws Exception { if (request.getRequestsCount() > 0) { - // we only test the first request and raise errors when subsequent sub-transactions do not - // fit. + // We only test the first request and raise errors when subsequent sub-transactions do not fit + // into the retrieve context. Currently this means that either all or none of the requests + // must be retrieve requests. final WrappedRequestsCase requestCase = request.getRequests(0).getWrappedRequestsCase(); switch (requestCase) { case RETRIEVE_REQUEST: @@ -219,9 +225,8 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa try { final UpdateEntity entity = new UpdateEntity( - grpcToCaosdb.getId(updateEntity.getId()), + grpcToCaosdb.getId(updateEntity.getId()), // ID is not handled by grpc convert grpcToCaosdb.convert(updateEntity.getRole())); - entity.setName(updateEntity.getName().isEmpty() ? null : updateEntity.getName()); grpcToCaosdb.convert(updateEntity, entity); addFileUpload(container, entity, updateRequest.getEntityRequest()); container.add(entity); @@ -348,8 +353,8 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa if (uploadFile == null) { entity.addError(ServerMessages.FILE_HAS_NOT_BEEN_UPLOAED); } else { - container.addFile(uploadFile.getTmpIdentifyer(), uploadFile); - entity.getFileProperties().setTmpIdentifyer(uploadFile.getTmpIdentifyer()); + container.addFile(uploadFile.getTmpIdentifier(), uploadFile); + entity.getFileProperties().setTmpIdentifier(uploadFile.getTmpIdentifier()); } } } diff --git a/src/main/java/org/caosdb/server/grpc/GeneralInfoServiceImpl.java b/src/main/java/org/caosdb/server/grpc/GeneralInfoServiceImpl.java index 9326643b23fd46a5b637ceca80a93cae329397cc..af283da1adf7ce9806338b42c14ec51fc612ee5c 100644 --- a/src/main/java/org/caosdb/server/grpc/GeneralInfoServiceImpl.java +++ b/src/main/java/org/caosdb/server/grpc/GeneralInfoServiceImpl.java @@ -53,7 +53,7 @@ public class GeneralInfoServiceImpl extends GeneralInfoServiceImplBase { final Integer major = Integer.parseInt(version[0]); final Integer minor = Integer.parseInt(version[1]); final Integer patch = Integer.parseInt(version[2]); - final String pre_release = version.length > 3 ? version[3] : null; + final String pre_release = version.length > 3 ? version[3] : ""; final String build = CaosDBServer.getServerProperty(ServerProperties.KEY_PROJECT_REVISTION); final VersionInfo versionInfo = diff --git a/src/main/java/org/caosdb/server/grpc/GrpcToCaosDBConverters.java b/src/main/java/org/caosdb/server/grpc/GrpcToCaosDBConverters.java index 302800711262ace87513eee9d5712420a4e496f5..c2007bebd52f29ce8d1a02fe9e0fcd913a8df798 100644 --- a/src/main/java/org/caosdb/server/grpc/GrpcToCaosDBConverters.java +++ b/src/main/java/org/caosdb/server/grpc/GrpcToCaosDBConverters.java @@ -70,6 +70,10 @@ public class GrpcToCaosDBConverters { return new GenericValue(valString); } + /** + * Set the content of {@code entity} to that of the grpc message object {@code from}. Also return + * {@code entity} at the end. + */ public EntityInterface convert(final Entity from, final EntityInterface entity) { entity.setName(from.getName().isEmpty() ? null : from.getName()); entity.setDescription(from.getDescription().isBlank() ? null : from.getDescription()); @@ -209,8 +213,8 @@ public class GrpcToCaosDBConverters { final StatementStatus defaultImportance) { final Collection<Property> result = new LinkedList<>(); propertiesList.forEach( - e -> { - result.add(convert(e, defaultImportance)); + prop -> { + result.add(convert(prop, defaultImportance)); }); return result; } diff --git a/src/main/java/org/caosdb/server/grpc/UploadBuffer.java b/src/main/java/org/caosdb/server/grpc/UploadBuffer.java index a955622008d994bd9b0b87aac624790dae6660b2..b341c33cbe9e0ca911c35aad144492cc2631da63 100644 --- a/src/main/java/org/caosdb/server/grpc/UploadBuffer.java +++ b/src/main/java/org/caosdb/server/grpc/UploadBuffer.java @@ -46,7 +46,7 @@ public class UploadBuffer { final FileProperties result = new FileProperties(null, tmpFile.getAbsolutePath(), tmpFile.length()); result.setFile(tmpFile); - result.setTmpIdentifyer(fileId); + result.setTmpIdentifier(fileId); return result; } } diff --git a/src/main/java/org/caosdb/server/jobs/core/MatchFileProp.java b/src/main/java/org/caosdb/server/jobs/core/MatchFileProp.java index cef8b2b8ae9764ceb1e4bd2636c2b532d7e9415b..249fc0b17ebe908a9a7ab9d13bfdb00d869ec630 100644 --- a/src/main/java/org/caosdb/server/jobs/core/MatchFileProp.java +++ b/src/main/java/org/caosdb/server/jobs/core/MatchFileProp.java @@ -46,7 +46,7 @@ public class MatchFileProp extends FilesJob { // descriptiveFileProperties is how the copied/uploaded/... file // ACTUALLY looks like. (path, checksum, size) final FileProperties descriptiveFileProperties = - getFile(normativeFileProperties.getTmpIdentifyer()); + getFile(normativeFileProperties.getTmpIdentifier()); if (descriptiveFileProperties != null) { checkChecksum(normativeFileProperties, descriptiveFileProperties); diff --git a/src/main/java/org/caosdb/server/jobs/core/PickUp.java b/src/main/java/org/caosdb/server/jobs/core/PickUp.java index 94a80836c863ea226a88e035201a2e2fb9fd1039..b0e04529fa059be33b5af99c47286a3d2a469cdb 100644 --- a/src/main/java/org/caosdb/server/jobs/core/PickUp.java +++ b/src/main/java/org/caosdb/server/jobs/core/PickUp.java @@ -46,12 +46,12 @@ public class PickUp extends EntityJob implements Observer { if (normativeFileProperties.isPickupable()) { try { entity.acceptObserver(this); - this.dropOffBoxPath = normativeFileProperties.getTmpIdentifyer(); + this.dropOffBoxPath = normativeFileProperties.getTmpIdentifier(); final FileProperties descriptiveFileProperties = FileSystem.pickUp(this.dropOffBoxPath, getRequestId()); normativeFileProperties.setFile(descriptiveFileProperties.getFile()); normativeFileProperties.setThumbnail(descriptiveFileProperties.getThumbnail()); - normativeFileProperties.setTmpIdentifyer(null); + normativeFileProperties.setTmpIdentifier(null); if (!normativeFileProperties.hasSize()) { normativeFileProperties.setSize(normativeFileProperties.getFile().length()); } diff --git a/src/main/java/org/caosdb/server/jobs/core/TestMail.java b/src/main/java/org/caosdb/server/jobs/core/TestMail.java index 210a9f59b879529f5f96954250556e88f60454be..793e6fe211f18c2d576501597c1189dac2444d46 100644 --- a/src/main/java/org/caosdb/server/jobs/core/TestMail.java +++ b/src/main/java/org/caosdb/server/jobs/core/TestMail.java @@ -43,12 +43,12 @@ public class TestMail extends FlagJob { CaosDBServer.getServerProperty(ServerProperties.KEY_NO_REPLY_EMAIL); @Override - protected void job(final String value) { - if (CaosDBServer.isDebugMode() && value != null) { - if (Utils.isRFC822Compliant(value)) { - final Mail m = new Mail(NAME, EMAIL, null, value, "Test mail", "This is a test mail."); + protected void job(final String recipient) { + if (CaosDBServer.isDebugMode() && recipient != null) { + if (Utils.isRFC822Compliant(recipient)) { + final Mail m = new Mail(NAME, EMAIL, null, recipient, "Test mail", "This is a test mail."); m.send(); - getContainer().addMessage(new Message("A mail has been send to " + value)); + getContainer().addMessage(new Message("A mail has been sent to " + recipient)); } else { getContainer().addMessage(ServerMessages.EMAIL_NOT_WELL_FORMED); } diff --git a/src/main/java/org/caosdb/server/resource/ScriptingResource.java b/src/main/java/org/caosdb/server/resource/ScriptingResource.java index 4629457f7bad9eeedfcaf680e6dc3fb5556e6726..6e7cf721cb11bf95df23396bc79d5691335708a6 100644 --- a/src/main/java/org/caosdb/server/resource/ScriptingResource.java +++ b/src/main/java/org/caosdb/server/resource/ScriptingResource.java @@ -152,7 +152,7 @@ public class ScriptingResource extends AbstractCaosDBServerResource { final FileProperties file = FileSystem.upload(item, this.getSRID()); deleteTmpFileAfterTermination(file); file.setPath(item.getName()); - file.setTmpIdentifyer(item.getFieldName()); + file.setTmpIdentifier(item.getFieldName()); files.add(file); form.add( new Parameter( diff --git a/src/main/java/org/caosdb/server/transaction/WriteTransaction.java b/src/main/java/org/caosdb/server/transaction/WriteTransaction.java index daaf78ec58de00553b0a15e040e5c5435265ec0c..1540ca79fdf557c3998f4b66072b4cb5466633a1 100644 --- a/src/main/java/org/caosdb/server/transaction/WriteTransaction.java +++ b/src/main/java/org/caosdb/server/transaction/WriteTransaction.java @@ -182,7 +182,7 @@ public class WriteTransaction extends Transaction<WritableContainer> // get file by tmpIdentifier final FileProperties f = - getContainer().getFiles().get(entity.getFileProperties().getTmpIdentifyer()); + getContainer().getFiles().get(entity.getFileProperties().getTmpIdentifier()); // is it there? if (f != null) { @@ -195,7 +195,7 @@ public class WriteTransaction extends Transaction<WritableContainer> final FileProperties thumbnail = getContainer() .getFiles() - .get(entity.getFileProperties().getTmpIdentifyer() + ".thumbnail"); + .get(entity.getFileProperties().getTmpIdentifier() + ".thumbnail"); if (thumbnail != null) { entity.getFileProperties().setThumbnail(thumbnail.getFile()); } else { @@ -251,7 +251,7 @@ public class WriteTransaction extends Transaction<WritableContainer> && !entity.getFileProperties().isPickupable()) { // dereference files (file upload only) final FileProperties f = - getContainer().getFiles().get(entity.getFileProperties().getTmpIdentifyer()); + getContainer().getFiles().get(entity.getFileProperties().getTmpIdentifier()); if (f != null) { entity.getFileProperties().setFile(f.getFile()); if (f.getThumbnail() != null) { @@ -260,7 +260,7 @@ public class WriteTransaction extends Transaction<WritableContainer> final FileProperties thumbnail = getContainer() .getFiles() - .get(entity.getFileProperties().getTmpIdentifyer() + ".thumbnail"); + .get(entity.getFileProperties().getTmpIdentifier() + ".thumbnail"); if (thumbnail != null) { entity.getFileProperties().setThumbnail(thumbnail.getFile()); } else { diff --git a/src/main/java/org/caosdb/server/utils/ServerMessages.java b/src/main/java/org/caosdb/server/utils/ServerMessages.java index 33a4b3005d91250b97cacfdc2af66de604dbf607..4197f2cf78cedb3fcf9dc0ea6648b6c3335a9da8 100644 --- a/src/main/java/org/caosdb/server/utils/ServerMessages.java +++ b/src/main/java/org/caosdb/server/utils/ServerMessages.java @@ -55,7 +55,7 @@ public class ServerMessages { new Message(MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, "Parsing failed."); public static final Message UNKNOWN_DATATYPE = - new Message(MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, "Unknown datatype."); + new Message(MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, "Unknown data type."); public static final Message UNKNOWN_IMPORTANCE = new Message(MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, "Unknown importance."); @@ -166,7 +166,7 @@ public class ServerMessages { new Message( MessageType.Error, MessageCode.MESSAGE_CODE_CANNOT_MOVE_FILE_TO_TARGET_PATH, - "Could not move file to it's target folder."); + "Could not move file to its target folder."); public static final Message CANNOT_PARSE_DATETIME_VALUE = new Message( @@ -190,7 +190,7 @@ public class ServerMessages { new Message( MessageType.Error, MessageCode.MESSAGE_CODE_CANNOT_PARSE_BOOL_VALUE, - "Cannot parse value to boolean (either 'true' or 'false', ignoring case)."); + "Cannot parse value to boolean (either 'true' or 'false', case insensitive)."); public static final Message CANNOT_CONNECT_TO_DATABASE = new Message( @@ -202,7 +202,7 @@ public class ServerMessages { new Message( MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, - "Request Body was not a well-formed xml."); + "Request body was not a well-formed xml."); public static final Message REQUEST_BODY_EMPTY = new Message(MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, "Request body was empty."); @@ -211,7 +211,7 @@ public class ServerMessages { new Message( MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, - "Request body didn't contain the expected Elements."); + "Request body didn't contain the expected elements."); public static final Message FILE_NOT_IN_DROPOFFBOX = new Message( @@ -348,7 +348,7 @@ public class ServerMessages { new Message(MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, "Cannot parse EntityACL."); public static final Message ROLE_DOES_NOT_EXIST = - new Message(MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, "User Role does not exist."); + new Message(MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, "User role does not exist."); public static final Message ENTITY_NAME_DUPLICATES = new Message( @@ -378,7 +378,7 @@ public class ServerMessages { new Message( MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, - "This password is too weak. It should be longer than 8 characters and sufficiently random. "); + "This password is too weak. It should be longer than 8 characters and sufficiently random."); public static final Message AFFILIATION_ERROR = new Message( @@ -396,19 +396,19 @@ public class ServerMessages { new Message( MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, - "QueryTemplates may not be defined by 'COUNT...' queries for consistency reasons."); + "QueryTemplates may not be defined by 'COUNT' queries for consistency reasons."); public static final Message QUERY_TEMPLATE_WITH_SELECT = new Message( MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, - "QueryTemplates may not be defined by 'SELECT... FROM...' queries for consistency reasons."); + "QueryTemplates may not be defined by 'SELECT ... FROM ...' queries for consistency reasons."); public static final Message QUERY_PARSING_ERROR = new Message( MessageType.Error, MessageCode.MESSAGE_CODE_QUERY_PARSING_ERROR, - "An error occured during the parsing of this query. Maybe you use a wrong syntax?"); + "An error occured during the parsing of this query. Maybe you were using a wrong syntax?"); public static final Message NAME_PROPERTIES_MUST_BE_TEXT = new Message( @@ -420,7 +420,7 @@ public class ServerMessages { new Message( MessageType.Warning, MessageCode.MESSAGE_CODE_PARENT_DUPLICATES_WARNING, - "This entity had parent duplicates. That is meaningless and only one parent had been inserted."); + "This entity had parent duplicates. That is meaningless and only one parent has been inserted."); public static final Message PARENT_DUPLICATES_ERROR = new Message( @@ -494,13 +494,13 @@ public class ServerMessages { new Message( MessageType.Error, MessageCode.MESSAGE_CODE_DATA_TYPE_INHERITANCE_AMBIGUOUS, - "The datatype which is to be inherited could not be detected due to divergent datatypes of at least two parents."); + "The data type which is to be inherited could not be detected due to divergent data types of at least two parents."); public static final Message DATA_TYPE_DOES_NOT_ACCEPT_COLLECTION_VALUES = new Message( MessageType.Error, MessageCode.MESSAGE_CODE_DATA_TYPE_DOES_NOT_ACCEPT_COLLECTION_VALUES, - "This datatype does not accept collections of values (e.g. Lists)."); + "This data type does not accept collections of values (e.g. Lists)."); public static final Message CANNOT_PARSE_UNIT = new Message( @@ -554,7 +554,7 @@ public class ServerMessages { new Message( MessageType.Warning, MessageCode.MESSAGE_CODE_PROPERTY_WITH_DATA_TYPE_OVERRIDE, - "This property overrides the datatype."); + "This property overrides the data type."); public static final Message PROPERTY_WITH_DESC_OVERRIDE = new Message( diff --git a/src/test/java/org/caosdb/server/database/InsertTest.java b/src/test/java/org/caosdb/server/database/InsertTest.java index 7b00cacfe7c3454539cb6823d62bc3af9b4d7ce7..b6b535c77700e55bfba67523d6250025b6ce3360 100644 --- a/src/test/java/org/caosdb/server/database/InsertTest.java +++ b/src/test/java/org/caosdb/server/database/InsertTest.java @@ -224,8 +224,6 @@ public class InsertTest { subp.setStatementStatus(StatementStatus.FIX); p2.addProperty(subp); - r.print(); - final LinkedList<EntityInterface> stage1Inserts = new LinkedList<EntityInterface>(); final LinkedList<EntityInterface> stage2Inserts = new LinkedList<EntityInterface>(); @@ -254,15 +252,6 @@ public class InsertTest { assertEquals((Integer) 2, stage2Inserts.get(0).getId()); assertEquals("V2", ((SingleValue) stage2Inserts.get(0).getValue()).toDatabaseString()); assertFalse(stage2Inserts.get(0).hasReplacement()); - - System.out.println("######### stage 1 #########"); - for (EntityInterface e : stage1Inserts) { - e.print(); - } - System.out.println("######### stage 2 #########"); - for (EntityInterface e : stage2Inserts) { - e.print(); - } } /** diff --git a/src/test/java/org/caosdb/server/scripting/TestServerSideScriptingCaller.java b/src/test/java/org/caosdb/server/scripting/TestServerSideScriptingCaller.java index 61be0c5c3a06319dbeb826a79ddf1c6e43a0d672..45b8e7f4408ca7186fbc2589b176d3c5eba113ba 100644 --- a/src/test/java/org/caosdb/server/scripting/TestServerSideScriptingCaller.java +++ b/src/test/java/org/caosdb/server/scripting/TestServerSideScriptingCaller.java @@ -186,7 +186,7 @@ public class TestServerSideScriptingCaller extends CaosDBTestClass { } /** - * Throw {@link CaosDBException} because tmpIdentifyer is null or empty. + * Throw {@link CaosDBException} because tmpIdentifier is null or empty. * * @throws FileNotFoundException * @throws CaosDBException @@ -222,7 +222,7 @@ public class TestServerSideScriptingCaller extends CaosDBTestClass { final ArrayList<FileProperties> files = new ArrayList<>(); final FileProperties f = new FileProperties(null, null, null); - f.setTmpIdentifyer("a2s3d4f5"); + f.setTmpIdentifier("a2s3d4f5"); f.setPath("testfile"); files.add(f); @@ -247,7 +247,7 @@ public class TestServerSideScriptingCaller extends CaosDBTestClass { final ArrayList<FileProperties> files = new ArrayList<>(); final FileProperties f = new FileProperties(null, null, null); - f.setTmpIdentifyer("a2s3d4f5"); + f.setTmpIdentifier("a2s3d4f5"); f.setFile(new File("blablabla_non_existing")); f.setPath("bla"); files.add(f); @@ -282,7 +282,7 @@ public class TestServerSideScriptingCaller extends CaosDBTestClass { final ArrayList<FileProperties> files = new ArrayList<>(); final FileProperties f = new FileProperties(null, null, null); - f.setTmpIdentifyer("a2s3d4f5"); + f.setTmpIdentifier("a2s3d4f5"); f.setFile(testFile); f.setPath("testfile"); files.add(f);