diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c23d36..f3beeb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,28 @@ # The LabKey Remote API Library for Java - Change Log -## version 7.4.0-SNAPSHOT +## version 8.1.0-SNAPSHOT *Released*: TBD -* + +## version 8.0.0 +*Released*: 2026-08-20 +* POTENTIALLY BREAKING CHANGES + * Eliminate the `RequestType` generic type parameter on `Command` + * Eliminate unnecessary `BaseSelect` interface + * Remove deprecated methods from `GetContainersResponse` and `GetUsersCommand` + * Update `StopImpersonatingCommand` to use the `stopImpersonatingApi` action. A successful execute() call now returns + status code 200 instead of 302. +* `ExecuteSqlCommand` now supports `setIncludeMetadata()` and `isIncludeMetadata()`. Use of this flag requires LabKey + Server v26.9+. +* Merge `ExecuteSqlCommand` into the `SelectRowsCommand` hierarchy to add `includeMetadata` support, eliminate redundant + code, and ensure future shared properties can be implemented in both easily. +* Add `ExecuteSqlCommand.quoteIdentifier()` helper method to quote identifiers that may have tricky characters +* Update Gradle, Gradle plugins, Commons Codec, Commons Logging, HttpClient, and JSON-java versions ## version 7.3.0 *Released*: 15 July 2026 * Update Gradle version and remove some deprecated syntax * Update HttpCore5 to 5.4.3 (CVE-2026-54399) and HttpClient5 to 5.5.2 -* Update Gradle plugins, Commons Codec, Commons Logging, and JSONObject versions +* Update Gradle plugins, Commons Codec, Commons Logging, and JSON-java versions ## version 7.2.0 *Released*: 17 February 2026 @@ -25,7 +39,7 @@ ## version 7.0.0 *Released*: 18 July 2025 -* Update Gradle, Gradle Plugins, HttpClient, and JSONObject versions +* Update Gradle, Gradle Plugins, HttpClient, and JSON-java versions * BREAKING CHANGES * The `SaveRowsCommand` has been updated to be a command wrapper for the `query-saveRows.api` * The `SaveRowsResponse` now wraps the response from the new `SaveRowsCommand` @@ -35,7 +49,7 @@ ## version 6.3.0 *Released*: 19 June 2025 -* Update Commons Codec, Commons Logging, Gradle, Gradle Plugins, HttpClient, HttpCore, and JSONObject versions +* Update Commons Codec, Commons Logging, Gradle, Gradle Plugins, HttpClient, HttpCore, and JSON-java versions * Remove defunct FileNotification API and uses * Update publishing method for new Maven Central API @@ -44,7 +58,7 @@ * Add support for `auditUserComment` field for assay import * Add support for `allowPlateMetadata`, `plateMetadata` fields for assay plate support * Deprecate `GetContainersResponse` permissions methods which are incompatible with LabKey Server v24.8+ -* Update Commons Codec, Commons Logging, Gradle, Gradle Plugins, HttpCore, and JSONObject versions +* Update Commons Codec, Commons Logging, Gradle, Gradle Plugins, HttpCore, and JSON-java versions ## version 6.1.0 *Released*: 26 February 2024 diff --git a/build.gradle b/build.gradle index ae208a6..bb75f70 100644 --- a/build.gradle +++ b/build.gradle @@ -70,7 +70,7 @@ repositories { group = "org.labkey.api" -version = "7.4.0-SNAPSHOT" +version = "8.1.0-SNAPSHOT" dependencies { api "org.json:json:${jsonObjectVersion}" diff --git a/gradle.properties b/gradle.properties index 14bc608..cbf976a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,15 +7,15 @@ artifactory_contextUrl=https://labkey.jfrog.io/artifactory sourceCompatibility=17 targetCompatibility=17 -gradlePluginsVersion=9.1.0 +gradlePluginsVersion=10.0.0 -commonsCodecVersion=1.22.0 +commonsCodecVersion=1.22.1 commonsLoggingVersion=1.4.0 -httpclient5Version=5.5.2 +httpclient5Version=5.6.4 httpcore5Version=5.4.3 -jsonObjectVersion=20260522 +jsonObjectVersion=20260719 junitVersion=4.13.2 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 61285a6..eddabd2 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a351597..ad7845b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index adff685..249efbb 100755 --- a/gradlew +++ b/gradlew @@ -20,7 +20,7 @@ ############################################################################## # -# Gradle start up script for POSIX generated by Gradle. +# gradlew start up script for POSIX generated by Gradle. # # Important for running: # @@ -29,7 +29,7 @@ # bash, then to run this script, type that shell name before the whole # command line, like: # -# ksh Gradle +# ksh gradlew # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. diff --git a/gradlew.bat b/gradlew.bat index c4bdd3a..a51ec4f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -19,12 +19,12 @@ @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -51,7 +51,7 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -65,29 +65,18 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/src/org/labkey/remoteapi/Command.java b/src/org/labkey/remoteapi/Command.java index e89e1e8..cca3832 100644 --- a/src/org/labkey/remoteapi/Command.java +++ b/src/org/labkey/remoteapi/Command.java @@ -58,7 +58,7 @@ * Note that this class is not thread-safe. Do not share instances of this class or its * descendants between threads, unless the descendant declares explicitly that it is thread-safe. */ -public abstract class Command implements HasRequiredVersion +public abstract class Command implements HasRequiredVersion { /** * A constant for the official JSON content type ("application/json") @@ -448,7 +448,7 @@ protected ResponseType createResponse(String text, int status, String contentTyp * @throws URISyntaxException Thrown if there is a problem parsing the base URL in the connection. */ - protected RequestType getHttpRequest(Connection connection, String folderPath) throws URISyntaxException + protected HttpUriRequest getHttpRequest(Connection connection, String folderPath) throws URISyntaxException { //construct a URI from connection base URI, folder path, and current parameters URI uri = createURI(connection, folderPath); @@ -461,7 +461,7 @@ protected RequestType getHttpRequest(Connection connection, String folderPath) t * @param uri the uri to convert * @return The HttpUriRequest instance. */ - protected abstract RequestType createRequest(URI uri); + protected abstract HttpUriRequest createRequest(URI uri); /** * Returns a full URI for this Command, including base URI, folder path, and query string. diff --git a/src/org/labkey/remoteapi/Connection.java b/src/org/labkey/remoteapi/Connection.java index adb0445..b26f335 100644 --- a/src/org/labkey/remoteapi/Connection.java +++ b/src/org/labkey/remoteapi/Connection.java @@ -380,8 +380,7 @@ public Connection stopImpersonating() throws IOException, CommandException { CommandResponse resp = new StopImpersonatingCommand().execute(this, _impersonatePath); - // on success, a 302 response is returned (this command disables redirects) - if (resp.getStatusCode() != 302) + if (resp.getStatusCode() != 200) throw new CommandException("Failed to stop impersonating"); _impersonateUser = null; diff --git a/src/org/labkey/remoteapi/GetCommand.java b/src/org/labkey/remoteapi/GetCommand.java index 4cf4f3a..1545be4 100644 --- a/src/org/labkey/remoteapi/GetCommand.java +++ b/src/org/labkey/remoteapi/GetCommand.java @@ -20,7 +20,7 @@ import java.net.URI; /** Base class for all commands that use get **/ -public abstract class GetCommand extends Command +public abstract class GetCommand extends Command { protected GetCommand(String controllerName, String actionName) { diff --git a/src/org/labkey/remoteapi/PostCommand.java b/src/org/labkey/remoteapi/PostCommand.java index 617b28f..2326a72 100644 --- a/src/org/labkey/remoteapi/PostCommand.java +++ b/src/org/labkey/remoteapi/PostCommand.java @@ -33,7 +33,7 @@ * specialized class in this library, the developer may invoke these APIs by creating an instance of * the {@link SimplePostCommand} class and setting the JSON object to post. */ -public abstract class PostCommand extends Command +public abstract class PostCommand extends Command { /** * Constructs a new PostCommand given a controller and action name. diff --git a/src/org/labkey/remoteapi/assay/nab/NAbRunsCommand.java b/src/org/labkey/remoteapi/assay/nab/NAbRunsCommand.java index 9206613..c2ab361 100644 --- a/src/org/labkey/remoteapi/assay/nab/NAbRunsCommand.java +++ b/src/org/labkey/remoteapi/assay/nab/NAbRunsCommand.java @@ -16,7 +16,7 @@ package org.labkey.remoteapi.assay.nab; import org.json.JSONObject; -import org.labkey.remoteapi.query.BaseQueryCommand; +import org.labkey.remoteapi.query.BaseSelectRowsCommand; /** * Command for obtaining information about the current assay definitions @@ -26,7 +26,7 @@ * you may use the various setters to filter this list to assays of a given * name, type or id. */ -public class NAbRunsCommand extends BaseQueryCommand +public class NAbRunsCommand extends BaseSelectRowsCommand { private String _assayName; private boolean _includeStats = true; diff --git a/src/org/labkey/remoteapi/query/BaseQueryCommand.java b/src/org/labkey/remoteapi/query/BaseQueryCommand.java index 75adce7..2260e43 100644 --- a/src/org/labkey/remoteapi/query/BaseQueryCommand.java +++ b/src/org/labkey/remoteapi/query/BaseQueryCommand.java @@ -26,13 +26,11 @@ public abstract class BaseQueryCommand extends PostCommand { - protected int _maxRows = -1; - protected int _offset = 0; - protected List _sorts; - protected List _filters; - protected ContainerFilter _containerFilter; + private int _maxRows = -1; + private int _offset = 0; + private List _sorts; + private ContainerFilter _containerFilter; private Map _queryParameters = new HashMap<>(); - private boolean _ignoreFilter = false; private boolean _includeMetadata = true; private boolean _includeTotalCount = true; @@ -129,52 +127,6 @@ public void addSort(String columnName, Sort.Direction direction) addSort(new Sort(columnName, direction)); } - /** - * Returns the current list of filters, or null if none are defined. - * - * @return The current list of filters. - */ - public List getFilters() - { - return _filters; - } - - /** - * Sets the current list of filters. - * - * @param filters The new list of filters. - */ - public void setFilters(List filters) - { - _filters = filters; - } - - /** - * Adds a new filter to the list. - * - * @param filter The new filter definition. - */ - public void addFilter(Filter filter) - { - if (_filters == null) - _filters = new ArrayList<>(); - _filters.add(filter); - } - - /** - * Constructs and adds a new filter to the list. This is equivalent to - * addFilter(new Filter(columnName, value, operator)) - * - * @param columnName The column name. - * @param value The filter value. - * @param operator The filter operator. - * @see org.labkey.remoteapi.query.Filter - */ - public void addFilter(String columnName, Object value, Filter.Operator operator) - { - addFilter(new Filter(columnName, value, operator)); - } - /** * Returns the container filter set for this command * @@ -196,20 +148,6 @@ public void setContainerFilter(ContainerFilter containerFilter) _containerFilter = containerFilter; } - public boolean isIgnoreFilter() - { - return _ignoreFilter; - } - - /** - * Pass true to ignore any filter that may be part of the chosen view. Defaults to false. - * @param ignoreFilter Set to 'true' to ignore the view filter. - */ - public void setIgnoreFilter(boolean ignoreFilter) - { - _ignoreFilter = ignoreFilter; - } - public boolean isIncludeMetadata() { return _includeMetadata; @@ -262,40 +200,37 @@ public JSONObject getJsonObject() { JSONObject json = new JSONObject(); + if (getContainerFilter() != null) + json.put("containerFilter", getContainerFilter().name()); + + if (!isIncludeTotalCount()) + json.put("includeTotalCount", isIncludeTotalCount()); + + if (!isIncludeMetadata()) + json.put("includeMetadata", isIncludeMetadata()); + + return json; + } + + protected void addOffsetAndMaxRows(JSONObject json, String offsetName, String maxRowsName) + { if (getOffset() > 0) - json.put("query.offset", getOffset()); + json.put(offsetName, getOffset()); if (getMaxRows() >= 0) - json.put("query.maxRows", getMaxRows()); - else - json.put("query.showRows", "all"); + json.put(maxRowsName, getMaxRows()); + } - if (null != getSorts() && getSorts().size() > 0) + protected JSONObject addSortAndParams(JSONObject json) + { + if (null != getSorts() && !getSorts().isEmpty()) json.put("query.sort", Sort.getSortQueryStringParam(getSorts())); - if (null != getFilters()) - { - for(Filter filter : getFilters()) - json.put("query." + filter.getQueryStringParamName(), filter.getQueryStringParamValue()); - } - - if (getContainerFilter() != null) - json.put("containerFilter", getContainerFilter().name()); - for (Map.Entry entry : getQueryParameters().entrySet()) { json.put("query.param." + entry.getKey(), entry.getValue()); } - if (!isIncludeTotalCount()) - json.put("includeTotalCount", isIncludeTotalCount()); - - if (!isIncludeMetadata()) - json.put("includeMetadata", isIncludeMetadata()); - - if (isIgnoreFilter()) - json.put("query.ignoreFilter", isIgnoreFilter()); - return json; } } diff --git a/src/org/labkey/remoteapi/query/BaseSelect.java b/src/org/labkey/remoteapi/query/BaseSelect.java deleted file mode 100644 index acb2108..0000000 --- a/src/org/labkey/remoteapi/query/BaseSelect.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2009-2026 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.labkey.remoteapi.query; - -import org.labkey.remoteapi.CommandException; -import org.labkey.remoteapi.Connection; - -import java.io.IOException; - -/** - * Common methods implemented by SelectRowsCommand and ExecuteSqlCommand - */ -public interface BaseSelect -{ - int getMaxRows(); - - void setMaxRows(int maxRows); - - int getOffset(); - - void setOffset(int offset); - - ContainerFilter getContainerFilter(); - - void setContainerFilter(ContainerFilter containerFilter); - - SelectRowsResponse execute(Connection connection, String folderPath) throws IOException, CommandException; - - double getRequiredVersion(); - - void setRequiredVersion(double requiredVersion); -} diff --git a/src/org/labkey/remoteapi/query/BaseSelectRowsCommand.java b/src/org/labkey/remoteapi/query/BaseSelectRowsCommand.java new file mode 100644 index 0000000..f13b5b6 --- /dev/null +++ b/src/org/labkey/remoteapi/query/BaseSelectRowsCommand.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2026 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.labkey.remoteapi.query; + +import org.json.JSONObject; +import org.labkey.remoteapi.CommandResponse; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class BaseSelectRowsCommand extends BaseQueryCommand +{ + private List _filters; + private boolean _ignoreFilter = false; + + public BaseSelectRowsCommand(String controllerName, String actionName) + { + super(controllerName, actionName); + } + + /** + * Returns the current list of filters, or null if none are defined. + * + * @return The current list of filters. + */ + public List getFilters() + { + return _filters; + } + + /** + * Sets the current list of filters. + * + * @param filters The new list of filters. + */ + public void setFilters(List filters) + { + _filters = filters; + } + + /** + * Adds a new filter to the list. + * + * @param filter The new filter definition. + */ + public void addFilter(Filter filter) + { + if (_filters == null) + _filters = new ArrayList<>(); + _filters.add(filter); + } + + /** + * Constructs and adds a new filter to the list. This is equivalent to + * addFilter(new Filter(columnName, value, operator)) + * + * @param columnName The column name. + * @param value The filter value. + * @param operator The filter operator. + * @see org.labkey.remoteapi.query.Filter + */ + public void addFilter(String columnName, Object value, Filter.Operator operator) + { + addFilter(new Filter(columnName, value, operator)); + } + + public boolean isIgnoreFilter() + { + return _ignoreFilter; + } + + /** + * Pass true to ignore any filter that may be part of the chosen view. Defaults to false. + * @param ignoreFilter Set to 'true' to ignore the view filter. + */ + public void setIgnoreFilter(boolean ignoreFilter) + { + _ignoreFilter = ignoreFilter; + } + + @Override + public JSONObject getJsonObject() + { + JSONObject json = super.getJsonObject(); + + // Note: SelectRows and ExecuteSql both support sort and param, but they differ in how they're conveyed (URL vs. JSON) + addSortAndParams(json); + + // Note: SelectRows and ExecuteSql both support offset and maxRows, but the property names are different + addOffsetAndMaxRows(json,"query.offset", "query.maxRows"); + + if (!json.has("query.maxRows")) + json.put("query.showRows", "all"); + + if (null != getFilters()) + { + for (Filter filter : getFilters()) + json.put("query." + filter.getQueryStringParamName(), filter.getQueryStringParamValue()); + } + + if (isIgnoreFilter()) + json.put("query.ignoreFilter", isIgnoreFilter()); + + return json; + } +} diff --git a/src/org/labkey/remoteapi/query/ExecuteSqlCommand.java b/src/org/labkey/remoteapi/query/ExecuteSqlCommand.java index 135d5c0..fdf90e6 100644 --- a/src/org/labkey/remoteapi/query/ExecuteSqlCommand.java +++ b/src/org/labkey/remoteapi/query/ExecuteSqlCommand.java @@ -16,10 +16,8 @@ package org.labkey.remoteapi.query; import org.json.JSONObject; -import org.labkey.remoteapi.PostCommand; import org.labkey.remoteapi.internal.EncodeUtils; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -35,19 +33,15 @@ * The response of this command is exactly the same as the * {@link org.labkey.remoteapi.query.SelectRowsCommand}, so the response object * will be of type {@link org.labkey.remoteapi.query.SelectRowsResponse}. + *

+ * JavaClientApiTest includes some testing of this command. */ -public class ExecuteSqlCommand extends PostCommand implements BaseSelect +public class ExecuteSqlCommand extends BaseQueryCommand { private String _schemaName; private String _sql; - private int _maxRows = -1; - private int _offset = 0; - private ContainerFilter _containerFilter; - private boolean _includeTotalCount = true; - private List _sorts; private boolean _saveInSession = false; private boolean _includeDetailsColumn = false; - private Map _queryParameters = new HashMap<>(); private boolean _wafEncoding = true; /** @@ -132,92 +126,13 @@ public void setSql(String sql) } /** - * Returns the current row limit value. Defaults to -1, meaning return all rows. - * @return The current row limit value. - */ - @Override - public int getMaxRows() - { - return _maxRows; - } - - /** - * Sets the current row limit value. If this is set to a positive value, only - * the first maxRows rows will be returned from the server. - * @param maxRows The maximim number of rows to return, or -1 to get all rows (default). - */ - @Override - public void setMaxRows(int maxRows) - { - _maxRows = maxRows; - } - - /** - * Returns the index of the first row in the resultset to return (defaults to 0). - * @return The current offset index. - */ - @Override - public int getOffset() - { - return _offset; - } - - /** - * Sets the index of the first row in the resultset to return from the server. - * Use this in conjunction with {@link #setMaxRows(int)} to return pages of - * rows at a time from the server. - * @param offset The current offset index. - */ - @Override - public void setOffset(int offset) - { - _offset = offset; - } - - /** - Include the total number of rows available (defaults to true). - If false totalCount will equal number of rows returned (equal to maxRows unless maxRows == 0). - @return indication of whether total count should be included or not - */ - public boolean isIncludeTotalCount() - { - return _includeTotalCount; - } - - /** - Include the total number of rows available (defaults to true). - If false totalCount will equal number of rows returned (equal to maxRows unless maxRows == 0). - @param includeTotalCount setting for whether to include the total count - */ - public void setIncludeTotalCount(boolean includeTotalCount) - { - _includeTotalCount = includeTotalCount; - } - - /** - A sort specification to apply over the rows returned by the SQL. In general, you should either include an - ORDER BY clause in your SQL, or provide a sort specification via this config property, but not both. - The value of this property should be a comma-delimited list of column names you want to sort by. - Use a - prefix to sort a column in descending order - (e.g., 'LastName,-Age' to sort first by LastName, then by Age descending). - @return the list of sorts to apply - */ - public List getSorts() - { - return _sorts; - } - - /** - A sort specification to apply over the rows returned by the SQL. In general, you should either include an - ORDER BY clause in your SQL, or provide a sort specification via this config property, but not both. - The value of this property should be a comma-delimited list of column names you want to sort by. - Use a - prefix to sort a column in descending order - (e.g., 'LastName,-Age' to sort first by LastName, then by Age descending). - @param sorts the sort specifications to apply to the query + * @param sorts the sort specifications to apply to the query + * @deprecated Use {@link #setSorts(List)} instead. */ + @Deprecated public void setSort(List sorts) { - _sorts = sorts; + setSorts(sorts); } /** @@ -266,47 +181,6 @@ public void setIncludeDetailsColumn(boolean includeDetailsColumn) _includeDetailsColumn = includeDetailsColumn; } - /** - Map of name (string)/value pairs for the values of parameters if the SQL references underlying queries - that are parameterized. - @return map of query parameters for the SQL references - */ - public Map getQueryParameters() - { - return _queryParameters; - } - - /** - Map of name (string)/value pairs for the values of parameters if the SQL references underlying queries - that are parameterized. - @param parameters a map of the named parameters to use in the underlying parameterized queries - */ - public void setQueryParameters(Map parameters) - { - _queryParameters = parameters; - } - - /** - * Returns the container filter set for this command - * @return the container filter (may be null) - */ - @Override - public ContainerFilter getContainerFilter() - { - return _containerFilter; - } - - /** - * Sets the container filter for the sql to be executed. - * This will cause the query to be executed over more than one container. - * @param containerFilter the filter to apply to the query (may be null) - */ - @Override - public void setContainerFilter(ContainerFilter containerFilter) - { - _containerFilter = containerFilter; - } - public boolean getWafEncoding() { return _wafEncoding; @@ -332,16 +206,10 @@ protected SelectRowsResponse createResponse(String text, int status, String cont @Override public JSONObject getJsonObject() { - JSONObject json = new JSONObject(); + JSONObject json = super.getJsonObject(); json.put("schemaName", getSchemaName()); json.put("sql", getWafEncoding() ? EncodeUtils.wafEncode(getSql()) : getSql()); - if (getMaxRows() >= 0) - json.put("maxRows", getMaxRows()); - if (getOffset() > 0) - json.put("offset", getOffset()); - if (getContainerFilter() != null) - json.put("containerFilter", getContainerFilter().name()); - json.put("includeTotalCount", isIncludeTotalCount()); + addOffsetAndMaxRows(json, "offset", "maxRows"); json.put("includeDetailsColumn", isIncludeDetailsColumn()); json.put("saveInSession", isSaveInSession()); @@ -352,15 +220,19 @@ public JSONObject getJsonObject() protected Map createParameterMap() { Map params = super.createParameterMap(); + JSONObject sortAndParams = addSortAndParams(new JSONObject()); - if (null != getSorts() && !getSorts().isEmpty()) - params.put("query.sort", Sort.getSortQueryStringParam(getSorts())); - - for (Map.Entry entry : getQueryParameters().entrySet()) + if (!sortAndParams.isEmpty()) { - params.put("query.param." + entry.getKey(), entry.getValue()); + params.putAll(sortAndParams.toMap()); } return params; } + + // Convenience method for quoting an identifier that may have tricky characters, including quotes + public static String quoteIdentifier(String identifier) + { + return "\"" + identifier.replace("\"", "\"\"") + "\""; + } } diff --git a/src/org/labkey/remoteapi/query/SelectRowsCommand.java b/src/org/labkey/remoteapi/query/SelectRowsCommand.java index 43b0779..3f903d5 100644 --- a/src/org/labkey/remoteapi/query/SelectRowsCommand.java +++ b/src/org/labkey/remoteapi/query/SelectRowsCommand.java @@ -47,8 +47,10 @@ * } * * + *

+ * JavaClientApiTest includes some testing of this command. */ -public class SelectRowsCommand extends BaseQueryCommand implements BaseSelect +public class SelectRowsCommand extends BaseSelectRowsCommand { private String _schemaName; private String _queryName; @@ -193,7 +195,7 @@ public JSONObject getJsonObject() if (null != getViewName()) json.put("query.viewName", getViewName()); - if (null != getColumns() && getColumns().size() > 0) + if (null != getColumns() && !getColumns().isEmpty()) { StringBuilder collist = new StringBuilder(); String sep = ""; diff --git a/src/org/labkey/remoteapi/query/SelectRowsResponse.java b/src/org/labkey/remoteapi/query/SelectRowsResponse.java index 5aa4d89..5f9d011 100644 --- a/src/org/labkey/remoteapi/query/SelectRowsResponse.java +++ b/src/org/labkey/remoteapi/query/SelectRowsResponse.java @@ -66,7 +66,7 @@ else if("date".equalsIgnoreCase(type)) * @param json The parsed JSONObject (or null if no JSON was returned * @param sourceCommand A copy of the command that created this response */ - public SelectRowsResponse(String text, int statusCode, String contentType, JSONObject json, Command sourceCommand) + public SelectRowsResponse(String text, int statusCode, String contentType, JSONObject json, Command sourceCommand) { super(text, statusCode, contentType, json, sourceCommand); } diff --git a/src/org/labkey/remoteapi/security/GetContainersResponse.java b/src/org/labkey/remoteapi/security/GetContainersResponse.java index 8bf91f2..cddea9f 100644 --- a/src/org/labkey/remoteapi/security/GetContainersResponse.java +++ b/src/org/labkey/remoteapi/security/GetContainersResponse.java @@ -33,33 +33,6 @@ public String getContainerId() return getProperty("id"); } - @Deprecated(forRemoval = true) - public Integer getUserPermissions() - { - return getUserPermissions(null); - } - - @Deprecated(forRemoval = true) - public Integer getUserPermissions(String containerPath) - { - Map containerInfo = findContainer(containerPath, getParsedData()); - return (null == containerInfo) ? null : ((Number)containerInfo.get("userPermissions")).intValue(); - } - - @Deprecated(forRemoval = true) - public Boolean hasPermission(int perm) - { - Integer userPerms = getUserPermissions(); - return (null == userPerms) ? null : userPerms == (userPerms | perm); - } - - @Deprecated(forRemoval = true) - public Boolean hasPermission(int perm, String containerPath) - { - Integer userPerms = getUserPermissions(containerPath); - return (null == userPerms) ? null : userPerms == (userPerms | perm); - } - protected Map findContainer(String containerPath, Map root) { if(null == containerPath) diff --git a/src/org/labkey/remoteapi/security/GetUsersCommand.java b/src/org/labkey/remoteapi/security/GetUsersCommand.java index d6ac6a1..e0fd124 100644 --- a/src/org/labkey/remoteapi/security/GetUsersCommand.java +++ b/src/org/labkey/remoteapi/security/GetUsersCommand.java @@ -82,18 +82,6 @@ public void setName(String name) _name = name; } - @Deprecated(forRemoval = true) // Remove in 7.0.0 - public Boolean getIncludeDeactivated() - { - return _includeInactive; - } - - @Deprecated(forRemoval = true) // Remove in 7.0.0 - public void setIncludeDeactivated(Boolean includeInactive) - { - _includeInactive = (null != includeInactive && includeInactive); - } - /** * @return Flag to request inactive users as well */ diff --git a/src/org/labkey/remoteapi/security/StopImpersonatingCommand.java b/src/org/labkey/remoteapi/security/StopImpersonatingCommand.java index 3549bb8..a48c4b4 100644 --- a/src/org/labkey/remoteapi/security/StopImpersonatingCommand.java +++ b/src/org/labkey/remoteapi/security/StopImpersonatingCommand.java @@ -15,13 +15,9 @@ */ package org.labkey.remoteapi.security; -import org.apache.hc.client5.http.classic.methods.HttpPost; -import org.apache.hc.client5.http.config.RequestConfig; import org.labkey.remoteapi.CommandResponse; import org.labkey.remoteapi.PostCommand; -import java.net.URI; - /** * Stop impersonating a user, group, or role(s). */ @@ -29,21 +25,6 @@ public class StopImpersonatingCommand extends PostCommand { public StopImpersonatingCommand() { - // TODO: At some point (when we're okay with breaking compatibility with pre-22.10 servers) switch this to - // stopImpersonatingApi.api, a true API action added 9/22 and then remove the redirect machinations below. - super("login", "stopImpersonating.api"); - } - - @Override - protected HttpPost createRequest(URI uri) - { - // Disable redirects just for this request - HttpPost request = super.createRequest(uri); - RequestConfig oldConfig = request.getConfig(); - RequestConfig.Builder builder = oldConfig != null ? RequestConfig.copy(oldConfig) : RequestConfig.custom(); - builder.setRedirectsEnabled(false); - request.setConfig(builder.build()); - - return request; + super("login", "stopImpersonatingApi.api"); } } diff --git a/src/org/labkey/remoteapi/test/Test.java b/src/org/labkey/remoteapi/test/Test.java index af58c66..7a5e211 100644 --- a/src/org/labkey/remoteapi/test/Test.java +++ b/src/org/labkey/remoteapi/test/Test.java @@ -24,22 +24,7 @@ import org.labkey.remoteapi.assay.nab.model.NAbNeutralizationResult; import org.labkey.remoteapi.assay.nab.model.NAbRun; import org.labkey.remoteapi.assay.nab.model.NAbSample; -import org.labkey.remoteapi.query.ContainerFilter; -import org.labkey.remoteapi.query.DeleteRowsCommand; -import org.labkey.remoteapi.query.ExecuteSqlCommand; -import org.labkey.remoteapi.query.Filter; -import org.labkey.remoteapi.query.GetQueriesCommand; -import org.labkey.remoteapi.query.GetQueriesResponse; -import org.labkey.remoteapi.query.GetSchemasCommand; -import org.labkey.remoteapi.query.GetSchemasResponse; -import org.labkey.remoteapi.query.InsertRowsCommand; -import org.labkey.remoteapi.query.RowsResponse; -import org.labkey.remoteapi.query.SelectRowsCommand; -import org.labkey.remoteapi.query.SelectRowsResponse; -import org.labkey.remoteapi.query.Sort; -import org.labkey.remoteapi.query.TruncateTableCommand; -import org.labkey.remoteapi.query.TruncateTableResponse; -import org.labkey.remoteapi.query.UpdateRowsCommand; +import org.labkey.remoteapi.query.*; import java.io.IOException; import java.util.Collections; @@ -55,7 +40,7 @@ public class Test public static void main(String[] args) throws Exception { - String baseUrl = "http://localhost:8080/labkey"; + String baseUrl = "http://localhost:8080"; Connection cn = args.length < 2 ? new Connection(baseUrl) : new Connection(baseUrl, args[0], args[1]); //Connection cn = new Connection(baseUrl, new ApiKeyCredentialsProvider("session:d7c3a4aeb283e3e54c4126a707908420")); //Connection cn = new Connection(baseUrl, new NetRcCredentialsProvider(baseUrl));