From b08cf27f8df76976e7e782eaf9aff507b55baf66 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Thu, 27 Oct 2022 17:28:22 +0300 Subject: [PATCH 01/90] ALFREDAPI-504 gradlew rebase fixup --- gradlew | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 gradlew diff --git a/gradlew b/gradlew old mode 100755 new mode 100644 From bcdbb109197df77f9f3b73f37397aca1b1b1f569 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Thu, 27 Oct 2022 17:43:20 +0300 Subject: [PATCH 02/90] ALFREDAPI-504 Drop apix-rest-v1 dependency from apix-impl --- apix-impl/build.gradle | 3 --- .../apix/alfresco/configuration/ConfigurationServiceImpl.java | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index b99f9dca..54c995a3 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -89,9 +89,6 @@ allprojects { dependencies { compile(project(":apix-interface")) - compile(project(":apix-rest-v1")) { - exclude group: 'org.alfresco' - } alfrescoProvided group: 'org.alfresco', name: 'alfresco-repository', version: alfresco_version alfrescoProvided group: 'org.alfresco', name: 'alfresco-remote-api', version: alfresco_version diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java index 736a90cb..17a26274 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java @@ -17,7 +17,6 @@ import eu.xenit.apix.node.ChildParentAssociation; import eu.xenit.apix.node.INodeService; import eu.xenit.apix.node.NodeMetadata; -import eu.xenit.apix.rest.v1.configuration.ConfigurationWebscript1; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.slf4j.Logger; @@ -44,7 +43,7 @@ public class ConfigurationServiceImpl implements ConfigurationService { private static final String QNAME_FOLDER = TYPE_FOLDER.toString(); private static final QName QNAME_NAME = new QName(PROP_NAME.toString()); - Logger logger = LoggerFactory.getLogger(ConfigurationWebscript1.class); + Logger logger = LoggerFactory.getLogger(ConfigurationServiceImpl.class); @Autowired IFileFolderService fileFolderService; From 838219f734bcbd08f6ad778859f3f3429f023abf Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Tue, 25 Oct 2022 22:46:08 +0300 Subject: [PATCH 03/90] ALFREDAPI-504 Replace Dynamic Extensions with Alfresco MVC --- apix-docker/72/docker-compose.yml | 28 +- apix-docker/build.gradle | 3 + apix-impl/build.gradle | 105 +-- .../eu/xenit/apix/SpringConfiguration.java | 12 + .../alfresco/ApixToAlfrescoConversion.java | 2 - .../apix/alfresco/WIP/WIPServiceImpl.java | 2 - .../alfresco/categories/CategoryService.java | 6 +- .../alfresco/comments/CommentService.java | 2 - .../ConfigurationServiceImpl.java | 9 +- .../apix/alfresco/content/ContentService.java | 2 - .../alfresco/dictionary/AspectService.java | 2 - .../dictionary/DictionaryService.java | 2 - .../apix/alfresco/dictionary/TypeService.java | 2 - .../filefolder/FileFolderService.java | 2 - .../apix/alfresco/metadata/NodeService.java | 7 +- .../apix/alfresco/people/PeopleService.java | 2 - .../permissions/PermissionService.java | 6 +- .../properties/PropertyServiceImpl.java | 6 +- .../apix/alfresco/search/SearchService.java | 2 - .../apix/alfresco/sites/SiteService.java | 6 +- .../transaction/TransactionService.java | 6 +- .../translation/TranslationService.java | 6 +- .../apix/alfresco/version/VersionService.java | 6 +- .../versionhistory/VersionHistoryService.java | 4 - .../eu/xenit/apix/alfresco/web/WebUtils.java | 7 +- ...AbstractApixAlfrescoWorkflowConvertor.java | 4 + .../workflow/WorkflowServiceActivitiImpl.java | 5 +- .../workflow/WorkflowServiceApsImpl.java | 7 +- apix-integrationtests/build.gradle | 70 +- apix-integrationtests/overrides.gradle | 12 +- .../apix/rest/staging/tests/WorkflowTest.java | 5 +- .../apix/rest/v1/tests/AllNodeInfoTest.java | 9 +- .../eu/xenit/apix/rest/v1/tests/BulkTest.java | 13 +- .../apix/rest/v1/tests/CommentsTest.java | 21 +- .../apix/rest/v1/tests/ConfigurationTest.java | 108 ++- .../apix/rest/v1/tests/CopyNodeTest.java | 28 +- .../apix/rest/v1/tests/CreateNodeTest.java | 14 +- .../apix/rest/v1/tests/DictionaryTest.java | 18 +- .../apix/rest/v1/tests/MetadataTest.java | 69 +- .../apix/rest/v1/tests/MoveNodeTest.java | 4 +- .../apix/rest/v1/tests/NodeContentTest.java | 191 ++-- .../apix/rest/v1/tests/NodesBaseTest.java | 14 +- .../apix/rest/v1/tests/PermissionsTest.java | 7 +- .../apix/rest/v1/tests/RestV1BaseTest.java | 90 +- .../rest/v1/tests/VersionHistoryTest.java | 147 ++- .../rest/v1/tests/temp/UploadFileTest.java | 108 +-- .../v1/tests/temp/V1SearchWebscriptTest.java | 3 +- .../apix/rest/v2/tests/AllNodeInfoTest.java | 9 +- .../tests/search/SearchServiceFacetsTest.java | 5 +- .../apix/tests/search/SearchServiceTest.java | 3 - .../tests/search/TermHitHighlightingTest.java | 6 +- .../workflow/WorkflowServiceBaseTest.java | 3 + apix-interface/build.gradle | 11 +- .../apix/configuration/Configurations.java | 6 +- .../main/java/eu/xenit/apix/data/QName.java | 4 +- .../java/eu/xenit/apix/node/INodeService.java | 2 +- .../eu/xenit/apix/search/SearchQuery.java | 6 + .../xenit/apix/search/json/TypeResolver.java | 6 +- .../translation/PropertyTranslationValue.java | 2 + .../eu/xenit/apix/utils/java8/Optional.java | 20 - apix-rest-v1/build.gradle | 76 +- .../rest/AlfredApiRestServletContext.java | 175 ++++ .../java/eu/xenit/apix/rest/SpringConfig.java | 12 + .../Jackson2ApixAbstractSerializer.java | 29 + .../Jackson2ApixNodeRefDeserializer.java | 29 + .../Jackson2ApixNodeRefSerializer.java | 12 + .../Jackson2ApixQnameDeserializer.java | 29 + .../jackson/Jackson2ApixQnameSerializer.java | 12 + .../rest/staging/ApixStagingWebscript.java | 34 - .../apix/rest/staging/RestStagingConfig.java | 8 - .../staging/workflow/WorkflowJsonParser.java | 10 - .../staging/workflow/WorkflowWebscript.java | 221 ++--- .../eu/xenit/apix/rest/v0/RestV0Config.java | 10 - .../ClassificationGetWebscript.java | 52 +- .../DictionaryServiceChecksumWebscript.java | 58 +- .../v0/metadata/MetadataBulkWebscript.java | 79 +- .../v0/metadata/MetadataGetWebscript.java | 59 +- .../v0/metadata/MetadataPostWebscript.java | 63 +- .../apix/rest/v0/search/SearchWebScript0.java | 81 +- .../xenit/apix/rest/v1/ApixV1Webscript.java | 31 +- .../apix/rest/v1/DocumentationWebscript.java | 407 ++++---- .../xenit/apix/rest/v1/GeneralWebscript.java | 39 +- .../apix/rest/v1/bulk/BulkWebscript1.java | 130 ++- .../rest/v1/bulk/IntermediateContent.java | 4 +- .../rest/v1/bulk/IntermediateResponse.java | 5 + .../v1/categories/CategoryWebScript1.java | 42 +- .../ConfigurationWebscript1.java | 151 +-- .../v1/dictionary/DictionaryWebScript1.java | 139 ++- .../v1/internal/ApixArgumentResolver.java | 93 +- .../apix/rest/v1/nodes/ChangeAclsOptions.java | 5 +- .../apix/rest/v1/nodes/InheritFromParent.java | 2 +- .../apix/rest/v1/nodes/NodesWebscript1.java | 871 ++++++++---------- .../apix/rest/v1/people/PeopleWebscript1.java | 84 +- .../v1/properties/PropertiesWebScript1.java | 58 +- .../apix/rest/v1/search/SearchWebScript1.java | 91 +- .../apix/rest/v1/sites/SitesWebscript1.java | 85 +- .../apix/rest/v1/temp/LogsWebscript.java | 55 +- .../xenit/apix/rest/v1/temp/WIPWebscript.java | 39 +- .../translation/TranslationsWebscript1.java | 46 +- .../VersionHistoryWebScript1.java | 158 ++-- .../WorkingcopiesWebscript1.java | 117 +-- .../xenit/apix/rest/v2/ApixV2Webscript.java | 12 +- .../apix/rest/v2/groups/GroupsWebscript.java | 98 +- .../apix/rest/v2/nodes/NodesWebscriptV2.java | 222 ++--- .../apix/rest/v2/people/PeopleWebscript.java | 111 +-- .../alfred-rest/api.delete.desc.xml | 11 + .../webscripts/alfred-rest/api.get.desc.xml | 11 + .../webscripts/alfred-rest/api.post.desc.xml | 11 + .../webscripts/alfred-rest/api.put.desc.xml | 11 + .../module/alfred-api/module-context.xml | 7 + .../module/alfred-api/module.properties | 52 ++ .../src/main/resources/application.properties | 2 + .../src/main/resources/log4j.properties | 3 +- .../apix/rest/DocumentationWebscriptTest.java | 134 +-- .../xenit/apix/rest/NodesWebscript1Test.java | 14 +- .../eu/xenit/apix/rest/TestDEWebscript1.java | 19 +- build.gradle | 62 +- de-swagger-reader/build.gradle | 6 +- .../swagger/reader/DESwaggerExtension.java | 11 - .../java/eu/xenit/swagger/reader/Reader.java | 2 - .../io/swagger/sample/reader/DEWebscript.java | 14 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 122 files changed, 2831 insertions(+), 2952 deletions(-) create mode 100644 apix-impl/src/main/java/eu/xenit/apix/SpringConfiguration.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/SpringConfig.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixAbstractSerializer.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixNodeRefDeserializer.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixNodeRefSerializer.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixQnameDeserializer.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixQnameSerializer.java delete mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/ApixStagingWebscript.java delete mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/RestStagingConfig.java delete mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowJsonParser.java delete mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/RestV0Config.java create mode 100644 apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.delete.desc.xml create mode 100644 apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.get.desc.xml create mode 100644 apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.post.desc.xml create mode 100644 apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.put.desc.xml create mode 100644 apix-rest-v1/src/main/resources/alfresco/module/alfred-api/module-context.xml create mode 100644 apix-rest-v1/src/main/resources/alfresco/module/alfred-api/module.properties create mode 100644 apix-rest-v1/src/main/resources/application.properties diff --git a/apix-docker/72/docker-compose.yml b/apix-docker/72/docker-compose.yml index 1c7a4894..67607fab 100644 --- a/apix-docker/72/docker-compose.yml +++ b/apix-docker/72/docker-compose.yml @@ -4,7 +4,7 @@ services: alfresco-core: image: ${DOCKER_IMAGE} ports: - - "${DOCKER_IP}::8080" + - "${DOCKER_IP}:8080:8080" volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped @@ -13,6 +13,14 @@ services: - TERM=xterm - GLOBAL_messaging.broker.url=failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true - GLOBAL_localTransform.core-aio.url=http://transform-core-aio:8090/ + ## Needed for Solr indexing + - GLOBAL_local.transform.service.enabled=true +# # Disable transformations and renditions +# - GLOBAL_contentPropertyRestrictions.enabled=false +# - GLOBAL_ooo.enabled=false +# - GLOBAL_jodconverter.enabled=false +# - GLOBAL_transform.service.enabled=false +# - GLOBAL_legacy.transform.service.enabled=false solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 @@ -32,15 +40,15 @@ services: - POSTGRES_DB=alfresco restart: unless-stopped - activemq: - image: alfresco/alfresco-activemq:5.16.1 - mem_limit: 1g - - transform-core-aio: - image: alfresco/alfresco-transform-core-aio:2.5.0 - environment: - JAVA_OPTS: " -Xms256m -Xmx512m" - ACTIVEMQ_URL: "nio://activemq:61616" +# activemq: +# image: alfresco/alfresco-activemq:5.16.1 +# mem_limit: 1g +# +# transform-core-aio: +# image: alfresco/alfresco-transform-core-aio:2.5.0 +# environment: +# JAVA_OPTS: " -Xms256m -Xmx512m" +# ACTIVEMQ_URL: "nio://activemq:61616" volumes: alfresco: diff --git a/apix-docker/build.gradle b/apix-docker/build.gradle index bcf85b0f..85b0dcf1 100644 --- a/apix-docker/build.gradle +++ b/apix-docker/build.gradle @@ -20,6 +20,9 @@ subprojects { dependencies { alfrescoAmp project(path: ":apix-impl:apix-impl-${subproject_alfresco_version}", configuration: 'ampArtifact') alfrescoAmp project(path: ':apix-integrationtests-model-amp', configuration: 'ampArchives') + alfrescoAmp project(path: ':apix-rest-v1', configuration: 'ampArtifact') + alfrescoSM "com.gradecak.alfresco-mvc:alfresco-mvc-rest:$mvc" + alfrescoSM files(jar) alfrescoAmp "eu.xenit:alfresco-dynamic-extensions-repo-${subproject_alfresco_version}:${de_version}@amp" } diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index 54c995a3..dd508d6c 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -21,13 +21,14 @@ subprojects { configurations { ampArtifact - dynamicExtensionsBundles +// dynamicExtensionsBundles } dependencies { - compile(project(":apix-impl")) - // Works for >5 too - dynamicExtensionsBundles(group: 'eu.xenit.swagger.ui', name: 'swagger-ui_5x', version: '1.3.0') { transitive = false } + implementation(project(":apix-impl")) +// dynamicExtensionsBundles(group: 'eu.xenit.swagger.ui', name: 'swagger-ui_5x', version: '1.1.0') { +// transitive = false +// } // Works for 6x too } publishing { @@ -49,7 +50,7 @@ subprojects { srcDirs = ['src/main/java', '../src/main/java'] } amp { - dynamicExtension() +// dynamicExtension() module("src/main/config/module.properties") } } @@ -65,7 +66,7 @@ subprojects { // We want to add 'alfresco-global.properties' etc to the module-specific folder in the AMP // (e.g. 'config/module/alfresco/module/apix-impl-51/') without hard-coding project name for each Alfresco version. amp { - deBundles = configurations.dynamicExtensionsBundles + files(jar) +// deBundles = configurations.dynamicExtensionsBundles + files(jar) into("config/alfresco/module/${project.name}") { from("${project.parent.projectDir}/config/alfresco-global.properties") from("${project.parent.projectDir}/config/log4j.properties") @@ -84,25 +85,25 @@ subprojects { allprojects { // allprojects also applies to shared code (under apix-impl/src) that needs to work in IntelliJ - apply plugin: 'eu.xenit.de' +// apply plugin: 'eu.xenit.de' apply plugin: 'eu.xenit.alfresco' dependencies { - compile(project(":apix-interface")) + implementation(project(":apix-interface")) alfrescoProvided group: 'org.alfresco', name: 'alfresco-repository', version: alfresco_version alfrescoProvided group: 'org.alfresco', name: 'alfresco-remote-api', version: alfresco_version - compile group: 'org.yaml', name: 'snakeyaml', version: '1.15' - compile group: 'javax.validation', name: 'validation-api', version: '1.1.0.Final' + implementation group: 'org.yaml', name: 'snakeyaml', version: '1.15' + implementation group: 'javax.validation', name: 'validation-api', version: '1.1.0.Final' - testCompile group: 'eu.xenit.de', name: 'annotations', version: de_version - testCompile group: 'org.alfresco', name: 'alfresco-repository', version: alfresco_repo_version - testCompile group: 'org.alfresco', name: 'alfresco-data-model', version: alfresco_dm_version - testCompile group: 'org.alfresco', name: 'alfresco-remote-api', version: alfresco_version +// testCompile group: 'eu.xenit.de', name: 'annotations', version: de_version + testImplementation group: 'org.alfresco', name: 'alfresco-repository', version: alfresco_repo_version + testImplementation group: 'org.alfresco', name: 'alfresco-data-model', version: alfresco_dm_version + testImplementation group: 'org.alfresco', name: 'alfresco-remote-api', version: alfresco_version - testCompile group: 'org.mockito', name: 'mockito-core', version: '2.25.1' - testCompile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.2' - testCompile group: 'eu.xenit.testing', name: 'integration-testing', version: '1.1.0' + testImplementation group: 'org.mockito', name: 'mockito-core', version: '2.25.1' + testImplementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.2' + testImplementation group: 'eu.xenit.testing', name: 'integration-testing', version: '1.1.0' } task generateVersionFile(type: Task) { @@ -131,39 +132,39 @@ public class Version { testLogging { events "PASSED", "FAILED", "SKIPPED" } } - jar { - // This BundleSymbolicName is also used in - // apix-impl/src/integration-test/java/eu/xenit/apix/tests/ApixImplBundleFilter.java - // to find which integration tests need to run, so when changing it, change it there too. - bnd( - 'Export-Package': 'eu.xenit.apix.*; -split-package:=merge-first', - 'Include-Resource': includeResource(configurations.compile), - 'Bundle-ClassPath': bundleClassPath(configurations.compile), - 'Bundle-SymbolicName': "${project.group}.${project.name}", - 'Bundle-Description': 'Alfred API: Java API and REST API', - 'Import-Package': 'org.springframework.beans.factory,' - + 'org.springframework.cglib.core,' - + 'org.springframework.cglib.proxy,' - // Unintuitively, the notation 'version="1.0"' means any version >= 1.0 - + 'org.json;version="1.0",' - // Alfresco >=7.3 uses a SLF4J version >2.0, so we need to override the default upper boundary of 2.0. - + 'org.slf4j.*;version="1.7",' - + '!com.google.appengine.api,' - + '!com.google.apphosting.api,' - + '!org.joda.convert,' - + '*' - ) - } - - alfrescoDynamicExtensions { - versions.dynamicExtensions = de_version - // Configure endpoint for installBundle task - repository { - endpoint { - protocol = project.hasProperty('protocol') ? project.protocol : 'http' - host = project.hasProperty('host') ? project.host : 'localhost' - port = project.hasProperty('port') ? project.port : 8080 - } - } - } +// jar { +// // This BundleSymbolicName is also used in +// // apix-impl/src/integration-test/java/eu/xenit/apix/tests/ApixImplBundleFilter.java +// // to find which integration tests need to run, so when changing it, change it there too. +// bnd( +// 'Export-Package': 'eu.xenit.apix.*; -split-package:=merge-first', +// 'Include-Resource': includeResource(configurations.compile), +// 'Bundle-ClassPath': bundleClassPath(configurations.compile), +// 'Bundle-SymbolicName': "${project.group}.${project.name}", +// 'Bundle-Description': 'Alfred API: Java API and REST API', +// 'Import-Package': 'org.springframework.beans.factory,' +// + 'org.springframework.cglib.core,' +// + 'org.springframework.cglib.proxy,' +// // Unintuitively, the notation 'version="1.0"' means any version >= 1.0 +// + 'org.json;version="1.0",' +// // Alfresco >=7.3 uses a SLF4J version >2.0, so we need to override the default upper boundary of 2.0. +// + 'org.slf4j.*;version="1.7",' +// + '!com.google.appengine.api,' +// + '!com.google.apphosting.api,' +// + '!org.joda.convert,' +// + '*' +// ) +// } + +// alfrescoDynamicExtensions { +// versions.dynamicExtensions = de_version +// // Configure endpoint for installBundle task +// repository { +// endpoint { +// protocol = project.hasProperty('protocol') ? project.protocol : 'http' +// host = project.hasProperty('host') ? project.host : 'localhost' +// port = project.hasProperty('port') ? project.port : 8080 +// } +// } +// } } diff --git a/apix-impl/src/main/java/eu/xenit/apix/SpringConfiguration.java b/apix-impl/src/main/java/eu/xenit/apix/SpringConfiguration.java new file mode 100644 index 00000000..2cdac337 --- /dev/null +++ b/apix-impl/src/main/java/eu/xenit/apix/SpringConfiguration.java @@ -0,0 +1,12 @@ +package eu.xenit.apix; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan(basePackageClasses = { + Version.class, +}) +public class SpringConfiguration { + +} diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/ApixToAlfrescoConversion.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/ApixToAlfrescoConversion.java index 68623640..4c89eb28 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/ApixToAlfrescoConversion.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/ApixToAlfrescoConversion.java @@ -1,7 +1,6 @@ package eu.xenit.apix.alfresco; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -21,7 +20,6 @@ @Component("eu.xenit.apix.alfresco.ApixToAlfrescoConversion") -@OsgiService public class ApixToAlfrescoConversion { private static final Logger logger = LoggerFactory.getLogger(ApixToAlfrescoConversion.class); diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/WIP/WIPServiceImpl.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/WIP/WIPServiceImpl.java index 3bc5a820..40ac8835 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/WIP/WIPServiceImpl.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/WIP/WIPServiceImpl.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.WIP; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.WIP.IWIPService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import org.alfresco.service.ServiceRegistry; @@ -13,7 +12,6 @@ /** * Created by jasper on 29/09/17. */ -@OsgiService @Service("eu.xenit.apix.WIP.WIPService") public class WIPServiceImpl implements IWIPService { diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/categories/CategoryService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/categories/CategoryService.java index f1a78259..5dca7f62 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/categories/CategoryService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/categories/CategoryService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.categories; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import com.google.common.collect.Iterables; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.categories.Category; @@ -19,10 +18,9 @@ import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; -@OsgiService -@Component("eu.xenit.apix.categories.ICategoryService") +@Service("eu.xenit.apix.categories.ICategoryService") public class CategoryService implements ICategoryService { @Autowired diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/comments/CommentService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/comments/CommentService.java index 2f5947b5..4432ce8c 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/comments/CommentService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/comments/CommentService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.comments; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.comments.Comment; import eu.xenit.apix.comments.Conversation; @@ -26,7 +25,6 @@ import org.springframework.stereotype.Service; @Service("eu.xenit.apix.comments.CommentService") -@OsgiService public class CommentService implements ICommentService { private final Logger logger = LoggerFactory.getLogger(CommentService.class); diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java index 17a26274..9bc25c6d 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java @@ -2,9 +2,6 @@ import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; import eu.xenit.apix.configuration.ConfigurationFile; import eu.xenit.apix.configuration.ConfigurationFileFlags; import eu.xenit.apix.configuration.ConfigurationService; @@ -22,7 +19,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; @@ -30,15 +27,13 @@ import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; import static org.alfresco.model.ContentModel.PROP_NAME; import static org.alfresco.model.ContentModel.TYPE_FOLDER; -@OsgiService -@Component("eu.xenit.apix.configuration.ConfigurationService") +@Service("eu.xenit.apix.configuration.ConfigurationService") public class ConfigurationServiceImpl implements ConfigurationService { private static final String QNAME_FOLDER = TYPE_FOLDER.toString(); diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/content/ContentService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/content/ContentService.java index cd35fe4c..01653725 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/content/ContentService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/content/ContentService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.content; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.content.IContentService; import eu.xenit.apix.node.INodeService; import java.io.InputStream; @@ -9,7 +8,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -@OsgiService @Component("eu.xenit.apix.content.IContentService") public class ContentService implements IContentService { diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/AspectService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/AspectService.java index 45674599..0278908c 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/AspectService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/AspectService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.dictionary; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.data.QName; import eu.xenit.apix.dictionary.aspects.AspectDefinition; @@ -16,7 +15,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -@OsgiService @Component("eu.xenit.apix.dictionary.aspects.IAspectService") public class AspectService implements IAspectService { diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/DictionaryService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/DictionaryService.java index 0fed7439..18313b7d 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/DictionaryService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/DictionaryService.java @@ -1,7 +1,6 @@ package eu.xenit.apix.alfresco.dictionary; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.dictionary.IDictionaryService; import eu.xenit.apix.dictionary.aspects.AspectDefinition; @@ -35,7 +34,6 @@ * Created by Michiel Huygen on 24/11/2015. */ -@OsgiService @Component("eu.xenit.apix.dictionary.IDictionaryService") public class DictionaryService implements IDictionaryService { diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/TypeService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/TypeService.java index 50951411..f4bb673e 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/TypeService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/TypeService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.dictionary; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.data.QName; import eu.xenit.apix.dictionary.types.ITypeService; @@ -18,7 +17,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -@OsgiService @Component("eu.xenit.apix.dictionary.types.ITypeService") public class TypeService implements ITypeService { diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/filefolder/FileFolderService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/filefolder/FileFolderService.java index c116bbb5..1f1295aa 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/filefolder/FileFolderService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/filefolder/FileFolderService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.filefolder; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.data.StoreRef; @@ -28,7 +27,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -@OsgiService @Component("eu.xenit.apix.filefolder.IFileFolderService") public class FileFolderService implements IFileFolderService { diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/metadata/NodeService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/metadata/NodeService.java index 3645c264..e911b3ca 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/metadata/NodeService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/metadata/NodeService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.metadata; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.node.ChildParentAssociation; import eu.xenit.apix.node.INodeService; @@ -59,14 +58,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; /** * Created by mhgam on 23/11/2015. */ -@OsgiService -@Component("eu.xenit.apix.alfresco.metadata.NodeService") +@Service("eu.xenit.apix.alfresco.metadata.NodeService") public class NodeService implements INodeService { private final static String NAMESPACE_BEGIN = "" + '{'; @@ -673,6 +671,7 @@ public void setContent(eu.xenit.apix.data.NodeRef node, eu.xenit.apix.data.Conte @Override + // TODO @Zlatin MVC Extract file name in ContentInputStream pojo public eu.xenit.apix.data.ContentInputStream getContent(eu.xenit.apix.data.NodeRef nodeRef) { final ContentReader reader; try { diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/people/PeopleService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/people/PeopleService.java index 02e8b0ab..73e07ca4 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/people/PeopleService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/people/PeopleService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.people; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.groups.Group; @@ -27,7 +26,6 @@ import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; -@OsgiService @Service("eu.xenit.apix.people.IPeopleService") @Primary public class PeopleService implements IPeopleService { diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/permissions/PermissionService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/permissions/PermissionService.java index 49156ba3..6709c33a 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/permissions/PermissionService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/permissions/PermissionService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.permissions; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.data.QName; @@ -27,13 +26,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; /** * Created by kenneth on 10.03.16. */ -@Component("eu.xenit.apix.permissions.IPermissionService") -@OsgiService +@Service("eu.xenit.apix.permissions.IPermissionService") public class PermissionService implements IPermissionService { private final static Logger logger = LoggerFactory.getLogger(PermissionService.class); diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/properties/PropertyServiceImpl.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/properties/PropertyServiceImpl.java index bd2ef91e..d49e3950 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/properties/PropertyServiceImpl.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/properties/PropertyServiceImpl.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.properties; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.dictionary.properties.IPropertyService; import eu.xenit.apix.properties.Properties; @@ -21,11 +20,10 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; -@OsgiService -@Component("eu.xenit.apix.properties.IPropertyService") +@Service("eu.xenit.apix.properties.IPropertyService") @Primary public class PropertyServiceImpl implements IPropertyService { diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/search/SearchService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/search/SearchService.java index 982c1e4b..f0890d98 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/search/SearchService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/search/SearchService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.search; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.alfresco.dictionary.PropertyService; import eu.xenit.apix.data.QName; @@ -32,7 +31,6 @@ import org.springframework.stereotype.Service; @Service("eu.xenit.apix.search.SearchService") -@OsgiService public class SearchService implements ISearchService { public static final int MAX_ITEMS_DEFAULT = 1000; diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/sites/SiteService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/sites/SiteService.java index e9cdbd8c..d81a3648 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/sites/SiteService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/sites/SiteService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.sites; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.sites.ISite; @@ -15,10 +14,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; -@OsgiService -@Component("eu.xenit.apix.alfresco.sites.SiteService") +@Service("eu.xenit.apix.alfresco.sites.SiteService") public class SiteService implements ISiteService { private final static Logger logger = LoggerFactory.getLogger(SiteService.class); diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/transaction/TransactionService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/transaction/TransactionService.java index 822a29e9..ddb6b132 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/transaction/TransactionService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/transaction/TransactionService.java @@ -1,15 +1,13 @@ package eu.xenit.apix.alfresco.transaction; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.transaction.ITransactionService; import java.util.concurrent.Callable; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.ServiceRegistry; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; -@OsgiService -@Component("eu.xenit.apix.alfresco.transaction.TransactionService") +@Service("eu.xenit.apix.alfresco.transaction.TransactionService") public class TransactionService implements ITransactionService { @Autowired diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/translation/TranslationService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/translation/TranslationService.java index a2f309d6..ecf377e7 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/translation/TranslationService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/translation/TranslationService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.translation; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.dictionary.IDictionaryService; import eu.xenit.apix.translation.ITranslationService; @@ -31,11 +30,10 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.extensions.surf.util.I18NUtil; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; -@Component("eu.xenit.apix.translation.ITranslationService") -@OsgiService +@Service("eu.xenit.apix.translation.ITranslationService") public class TranslationService implements ITranslationService { private static final Logger logger = LoggerFactory.getLogger(TranslationService.class); diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/version/VersionService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/version/VersionService.java index 17f80264..0eec1e24 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/version/VersionService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/version/VersionService.java @@ -1,13 +1,11 @@ package eu.xenit.apix.alfresco.version; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.Version; import eu.xenit.apix.version.IVersionService; import eu.xenit.apix.version.VersionDescription; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; -@OsgiService -@Component("eu.xenit.apix.version.IVersionService") +@Service("eu.xenit.apix.version.IVersionService") public class VersionService implements IVersionService { @Override diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/versionhistory/VersionHistoryService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/versionhistory/VersionHistoryService.java index 43ee72d7..06d23589 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/versionhistory/VersionHistoryService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/versionhistory/VersionHistoryService.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.versionhistory; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.data.QName; @@ -10,7 +9,6 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; -import java.util.Collection.*; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -20,9 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -@OsgiService @Service("eu.xenit.apix.versionhistory.VersionHistoryService") - public class VersionHistoryService implements IVersionHistoryService { private ApixToAlfrescoConversion c; diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/web/WebUtils.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/web/WebUtils.java index e8f74be1..cf6d4bdb 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/web/WebUtils.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/web/WebUtils.java @@ -1,16 +1,15 @@ package eu.xenit.apix.alfresco.web; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.web.IWebUtils; import org.alfresco.repo.admin.SysAdminParams; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; /** * Provides utility functions to access information about the current web context */ -@Component("eu.xenit.apix.web.WebUtils") -@OsgiService + +@Service("eu.xenit.apix.web.WebUtils") public class WebUtils implements IWebUtils { @Autowired diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/workflow/AbstractApixAlfrescoWorkflowConvertor.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/workflow/AbstractApixAlfrescoWorkflowConvertor.java index 5fca349a..22c121da 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/workflow/AbstractApixAlfrescoWorkflowConvertor.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/workflow/AbstractApixAlfrescoWorkflowConvertor.java @@ -26,6 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; public abstract class AbstractApixAlfrescoWorkflowConvertor extends AbstractApixWorkflowConvertor { @@ -81,10 +82,13 @@ public abstract class AbstractApixAlfrescoWorkflowConvertor extends AbstractApix @Autowired protected ApixToAlfrescoConversion c; @Autowired + @Qualifier("WorkflowService") protected WorkflowService workflowService; @Autowired + @Qualifier("MessageService") private MessageService messageService; @Autowired + @Qualifier("NamespaceService") private NamespaceService namespaceService; protected static void setOwner(final WorkflowService ws, final String taskID, final String userName) { diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/workflow/WorkflowServiceActivitiImpl.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/workflow/WorkflowServiceActivitiImpl.java index b70143f4..824d4ba9 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/workflow/WorkflowServiceActivitiImpl.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/workflow/WorkflowServiceActivitiImpl.java @@ -1,6 +1,5 @@ package eu.xenit.apix.alfresco.workflow; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.alfresco.workflow.activiti.query.ApixHistoricInstanceQuery; import eu.xenit.apix.alfresco.workflow.utils.DebugHelper; @@ -32,8 +31,9 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; -@OsgiService +@Service public class WorkflowServiceActivitiImpl implements IWorkflowService { private final Logger logger = LoggerFactory.getLogger(WorkflowServiceActivitiImpl.class); @@ -56,6 +56,7 @@ public class WorkflowServiceActivitiImpl implements IWorkflowService { private AbstractApixQueryConverter apixWfProcQueryConverter; @Autowired + @Qualifier("WorkflowService") private WorkflowService workflowService; @PostConstruct diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/workflow/WorkflowServiceApsImpl.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/workflow/WorkflowServiceApsImpl.java index 8eacb4d2..60da6616 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/workflow/WorkflowServiceApsImpl.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/workflow/WorkflowServiceApsImpl.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.github.dynamicextensionsalfresco.osgi.OsgiService; import eu.xenit.apix.alfresco.ApixSpringConfiguration; import eu.xenit.apix.alfresco.workflow.aps.ApsFormDefinition; import eu.xenit.apix.alfresco.workflow.aps.ApsFormField; @@ -34,14 +33,16 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.commons.codec.binary.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; -@OsgiService +@Service public class WorkflowServiceApsImpl implements IWorkflowService { @Autowired @@ -250,7 +251,7 @@ public Workflow startWorkflow(String definitionKeyOrId, Map() { @@ -199,7 +200,7 @@ public Object execute() throws Throwable { jsonString = json(String.format("[{'url':'%s','method':'%s','body':%s}]", firstPostUrl, "post", firstJsonBody)); final HttpPost httpPost2 = new HttpPost(url); - httpPost2.setEntity(new StringEntity(jsonString)); + httpPost2.setEntity(new StringEntity(jsonString, ContentType.APPLICATION_JSON)); transactionService.getRetryingTransactionHelper() .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { @Override @@ -221,7 +222,7 @@ public Object execute() throws Throwable { jsonString = json(String.format("[{'url':'%s','method':'%s','body':%s}]", secondPostUrl, "post", secondJsonBody)); final HttpPost httpPost3 = new HttpPost(url); - httpPost3.setEntity(new StringEntity(jsonString)); + httpPost3.setEntity(new StringEntity(jsonString, ContentType.APPLICATION_JSON)); transactionService.getRetryingTransactionHelper() .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { @Override @@ -301,7 +302,7 @@ public void testPutBulk() throws IOException { String firstJsonBody = String.format("{'parent':'%s'}", mainFolderRef); String jsonString = json( String.format("[{'url':'%s', 'method':'%s', 'body':%s}]", firstPutUrl, "put", firstJsonBody)); - httpPost.setEntity(new StringEntity(jsonString)); + httpPost.setEntity(new StringEntity(jsonString, ContentType.APPLICATION_JSON)); transactionService.getRetryingTransactionHelper() .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { @@ -337,7 +338,7 @@ public void testDelete() throws IOException { String firstDeleteUrl = removePrefixAndAuthenticate( makeNodesUrl(initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME), "admin", "admin")); String jsonString = json(String.format("[{'url':'%s', 'method':'%s'}]", firstDeleteUrl, "delete")); - httpPost.setEntity(new StringEntity(jsonString)); + httpPost.setEntity(new StringEntity(jsonString, ContentType.APPLICATION_JSON)); transactionService.getRetryingTransactionHelper() .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { @@ -356,7 +357,7 @@ public Object execute() throws Throwable { "admin")); jsonString = json(String.format("[{'url':'%s', 'method':'%s', 'body':{}}]", secondDeleteUrl, "delete")); final HttpPost httpPost2 = new HttpPost(url); - httpPost2.setEntity(new StringEntity(jsonString)); + httpPost2.setEntity(new StringEntity(jsonString, ContentType.APPLICATION_JSON)); transactionService.getRetryingTransactionHelper() .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { @Override diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CommentsTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CommentsTest.java index e59a5559..a5eb9b50 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CommentsTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CommentsTest.java @@ -1,6 +1,7 @@ package eu.xenit.apix.rest.v1.tests; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -23,6 +24,7 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.utils.URIBuilder; +import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -139,7 +141,7 @@ public void testPutContent() throws IOException { HttpPut req = new HttpPut(url); final CloseableHttpClient checkoutHttpclient = HttpClients.createDefault(); String checkoutJsonString = "{ \"content\" : \"new content\" }"; - req.setEntity(new StringEntity(checkoutJsonString)); + req.setEntity(new StringEntity(checkoutJsonString, ContentType.APPLICATION_JSON)); String result = ""; try (CloseableHttpResponse response = checkoutHttpclient.execute(req)) { @@ -160,7 +162,7 @@ public void testPutContentOnContent() throws IOException { HttpPut req = new HttpPut(url); final CloseableHttpClient checkoutHttpclient = HttpClients.createDefault(); String checkoutJsonString = "{ \"content\" : \"new content\" }"; - req.setEntity(new StringEntity(checkoutJsonString)); + req.setEntity(new StringEntity(checkoutJsonString, ContentType.APPLICATION_JSON)); String result = ""; try (CloseableHttpResponse response = checkoutHttpclient.execute(req)) { @@ -170,20 +172,25 @@ public void testPutContentOnContent() throws IOException { } @Test - public void testDeleteComment() throws IOException { + public void testDeleteComment() throws IOException, InterruptedException { HashMap initializedRefs = init(); String url = makeCommentsUrl(initializedRefs.get(COMMENTNODE1), "admin", "admin"); HttpDelete req = new HttpDelete(url); final CloseableHttpClient checkoutHttpclient = HttpClients.createDefault(); - String result = ""; try (CloseableHttpResponse response = checkoutHttpclient.execute(req)) { - result = EntityUtils.toString(response.getEntity()); + EntityUtils.toString(response.getEntity()); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); } - assertEquals(false, nodeService.exists(initializedRefs.get(COMMENTNODE1))); + // Alfresco Cache is lagging behind... + Thread.sleep(2000); + + boolean exists = this.transactionHelper.doInTransaction( + () -> nodeService.exists(initializedRefs.get(COMMENTNODE1)), true, true + ); + assertFalse(exists); } @Test @@ -216,7 +223,7 @@ public void testAppendComments() throws IOException { HttpPost req = new HttpPost(url); String checkoutJsonString = "{ \"content\" : \"new content\" }"; - req.setEntity(new StringEntity(checkoutJsonString)); + req.setEntity(new StringEntity(checkoutJsonString, ContentType.APPLICATION_JSON)); final CloseableHttpClient checkoutHttpclient = HttpClients.createDefault(); String result = ""; try (CloseableHttpResponse response = checkoutHttpclient.execute(req)) { diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java index c441ad34..22d3d0e2 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java @@ -21,6 +21,7 @@ import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.transaction.TransactionService; +import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.client.fluent.Request; import org.apache.http.util.EntityUtils; @@ -34,6 +35,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.MediaType; /** * Created by kenneth on 14.03.16. @@ -83,35 +85,33 @@ public void setup() { TransactionService transactionService = serviceRegistry.getTransactionService(); - RetryingTransactionHelper.RetryingTransactionCallback txnWork = new RetryingTransactionHelper.RetryingTransactionCallback() { - public Object execute() throws Exception { - eu.xenit.apix.data.NodeRef dataDictionary = apixFileFolderService.getDataDictionary(); - eu.xenit.apix.data.NodeRef testFolder = apixFileFolderService - .createFolder(dataDictionary, "ConfigurationTests"); - - jsonNodeRef = nodeService - .createNode(testFolder, "xyz.json", new QName(ContentModel.TYPE_CONTENT.toString())); - ByteArrayInputStream jsonContent = new ByteArrayInputStream("{\"contents\": \"abc\"}".getBytes()); - contentService.setContent(jsonNodeRef, jsonContent, "abc.json"); - - yamlNodeRef = nodeService - .createNode(testFolder, "xyz.yaml", new QName(ContentModel.TYPE_CONTENT.toString())); - ByteArrayInputStream yamlContent = new ByteArrayInputStream("contents: abc".getBytes()); - contentService.setContent(yamlNodeRef, yamlContent, "abc.yaml"); - - otherNodeRef = nodeService - .createNode(testFolder, "xyz.json.disabled", new QName(ContentModel.TYPE_CONTENT.toString())); - ByteArrayInputStream otherContent = new ByteArrayInputStream("{\"contents\": \"other\"}".getBytes()); - contentService.setContent(otherNodeRef, otherContent, "abc.json"); - - NodeRef subFolder = apixFileFolderService.createFolder(testFolder, "subFolder"); - - yamlsubNodeRef = nodeService - .createNode(subFolder, "sub.yaml", new QName(ContentModel.TYPE_CONTENT.toString())); - ByteArrayInputStream yamlSubContent = new ByteArrayInputStream("contents: sub".getBytes()); - contentService.setContent(yamlsubNodeRef, yamlSubContent, "abc.yaml"); - return null; - } + RetryingTransactionHelper.RetryingTransactionCallback txnWork = () -> { + NodeRef dataDictionary = apixFileFolderService.getDataDictionary(); + NodeRef testFolder = apixFileFolderService + .createFolder(dataDictionary, "ConfigurationTests"); + + jsonNodeRef = nodeService + .createNode(testFolder, "xyz.json", new QName(ContentModel.TYPE_CONTENT.toString())); + ByteArrayInputStream jsonContent = new ByteArrayInputStream("{\"contents\": \"abc\"}".getBytes()); + contentService.setContent(jsonNodeRef, jsonContent, "abc.json"); + + yamlNodeRef = nodeService + .createNode(testFolder, "xyz.yaml", new QName(ContentModel.TYPE_CONTENT.toString())); + ByteArrayInputStream yamlContent = new ByteArrayInputStream("contents: abc".getBytes()); + contentService.setContent(yamlNodeRef, yamlContent, "abc.yaml"); + + otherNodeRef = nodeService + .createNode(testFolder, "xyz.json.disabled", new QName(ContentModel.TYPE_CONTENT.toString())); + ByteArrayInputStream otherContent = new ByteArrayInputStream("{\"contents\": \"other\"}".getBytes()); + contentService.setContent(otherNodeRef, otherContent, "abc.json"); + + NodeRef subFolder = apixFileFolderService.createFolder(testFolder, "subFolder"); + + yamlsubNodeRef = nodeService + .createNode(subFolder, "sub.yaml", new QName(ContentModel.TYPE_CONTENT.toString())); + ByteArrayInputStream yamlSubContent = new ByteArrayInputStream("contents: sub".getBytes()); + contentService.setContent(yamlsubNodeRef, yamlSubContent, "abc.yaml"); + return null; }; transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, false, true); @@ -127,7 +127,11 @@ private String makeBasePath() { public void testConfigurationGet() throws IOException, JSONException { String requestUrl = makeBasePath(); - HttpResponse response = Request.Get(requestUrl).execute().returnResponse(); + HttpResponse response = Request + .Get(requestUrl) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .execute() + .returnResponse(); assertEquals(200, response.getStatusLine().getStatusCode()); @@ -147,7 +151,7 @@ public void testConfigurationGet() throws IOException, JSONException { assertEquals("{\"contents\": \"abc\"}", jsonFile.optString("content")); } - assertEquals(2, jsonFile.length()); + assertEquals(jsonFile.toString(), 2, jsonFile.length()); } } @@ -156,7 +160,11 @@ public void testConfigurationGet() throws IOException, JSONException { public void testConfigurationGetFields() throws IOException, JSONException { String requestUrl = makeBasePath() + "&fields=nodeRef,path,metadata,parsedContent"; - HttpResponse response = Request.Get(requestUrl).execute().returnResponse(); + HttpResponse response = Request + .Get(requestUrl) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .execute() + .returnResponse(); assertEquals(200, response.getStatusLine().getStatusCode()); @@ -168,7 +176,7 @@ public void testConfigurationGetFields() throws IOException, JSONException { for (int i = 0; i < jsonFiles.length(); i++) { JSONObject jsonFile = jsonFiles.getJSONObject(i); - assertEquals(4, jsonFile.length()); + assertEquals(jsonFile.toString(), 4, jsonFile.length()); String nodeRef = jsonFile.optString("nodeRef"); assertNotNull(nodeRef); @@ -203,7 +211,11 @@ public void testConfigurationGetFields() throws IOException, JSONException { public void testConfigurationFilterFields() throws IOException, JSONException { String requestUrl = makeBasePath() + "&filter.name=" + URLEncoder.encode("\\.yaml$", "UTF-8"); - HttpResponse response = Request.Get(requestUrl).execute().returnResponse(); + HttpResponse response = Request + .Get(requestUrl) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .execute() + .returnResponse(); assertEquals(200, response.getStatusLine().getStatusCode()); @@ -224,7 +236,11 @@ public void testConfigurationFilterFields() throws IOException, JSONException { public void testConfigurationSubdirectory() throws IOException, JSONException { String requestUrl = makeBasePath() + "/subFolder"; - HttpResponse response = Request.Get(requestUrl).execute().returnResponse(); + HttpResponse response = Request + .Get(requestUrl) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .execute() + .returnResponse(); assertEquals(200, response.getStatusLine().getStatusCode()); @@ -243,19 +259,17 @@ public void testConfigurationSubdirectory() throws IOException, JSONException { @After public void cleanUp() { - RetryingTransactionHelper.RetryingTransactionCallback txnWork = new RetryingTransactionHelper.RetryingTransactionCallback() { - public Object execute() throws Exception { - try { - eu.xenit.apix.data.NodeRef dataDictionary = apixFileFolderService.getDataDictionary(); - eu.xenit.apix.data.NodeRef testFolder = apixFileFolderService - .getChildNodeRef(dataDictionary, "ConfigurationTests"); - removeTestNode(new org.alfresco.service.cmr.repository.NodeRef(testFolder.toString())); - } catch (RuntimeException ex) { - logger.debug("Did not need to remove mainTestFolder because it did not exist"); - //ex.printStackTrace(); - } - return null; + RetryingTransactionHelper.RetryingTransactionCallback txnWork = () -> { + try { + NodeRef dataDictionary = apixFileFolderService.getDataDictionary(); + NodeRef testFolder = apixFileFolderService + .getChildNodeRef(dataDictionary, "ConfigurationTests"); + removeTestNode(new org.alfresco.service.cmr.repository.NodeRef(testFolder.toString())); + } catch (RuntimeException ex) { + logger.debug("Did not need to remove mainTestFolder because it did not exist"); + //ex.printStackTrace(); } + return null; }; TransactionService transactionService = serviceRegistry.getTransactionService(); transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, false, true); diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java index 3a7c059b..77ad1bfd 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java @@ -5,6 +5,8 @@ import eu.xenit.apix.data.QName; import eu.xenit.apix.node.INodeService; import eu.xenit.apix.rest.v1.nodes.CreateNodeOptions; + +import java.io.IOException; import java.util.HashMap; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -47,7 +49,7 @@ public void setup() { } @Test - public void testCopyFileNode() { + public void testCopyFileNode() throws IOException { CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, null, null, null , copyFromFile); NodeRef newRef = transactionService.getRetryingTransactionHelper() @@ -58,7 +60,7 @@ public void testCopyFileNode() { } @Test - public void testCopyFileNodeWithAspectsToRemove() { + public void testCopyFileNodeWithAspectsToRemove() throws IOException { transactionService.getRetryingTransactionHelper() .doInTransaction(() -> { serviceRegistry.getNodeService().addAspect(c.alfresco(copyFromFile), ContentModel.ASPECT_TEMPORARY, new HashMap<>()); @@ -78,7 +80,7 @@ public void testCopyFileNodeWithAspectsToRemove() { } @Test - public void testCopyFolderNode() { + public void testCopyFolderNode() throws IOException { CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, null, null, null , copyFromFolder); NodeRef newRef = transactionService.getRetryingTransactionHelper() @@ -89,7 +91,7 @@ public void testCopyFolderNode() { } @Test - public void testCopyFileWithName() { + public void testCopyFileWithName() throws IOException { final String newName = "Copy"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, newName, null, null, copyFromFile); @@ -101,7 +103,7 @@ public void testCopyFileWithName() { } @Test - public void testCopyFolderWithName() { + public void testCopyFolderWithName() throws IOException { final String newName = "CopiedFolder"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, newName, null, null, copyFromFolder); @@ -113,7 +115,7 @@ public void testCopyFolderWithName() { } @Test - public void testCopyFileDuplicateName() { + public void testCopyFileDuplicateName() throws IOException { final String duplicateName = "duplicateName"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, duplicateName, null, null, copyFromFile); @@ -134,7 +136,7 @@ public void testCopyFileDuplicateName() { } @Test - public void testCopyFolderDuplicateName() { + public void testCopyFolderDuplicateName() throws IOException { final NodeRef childRef = nodeService.getChildAssociations(mainTestFolder).get(0).getTarget(); final String newName = nodeService.getMetadata(childRef).properties.get(c.apix(ContentModel.PROP_NAME)).get(0); CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, newName, @@ -147,7 +149,7 @@ public void testCopyFolderDuplicateName() { } @Test - public void testCopyNodeWithProperties() { + public void testCopyNodeWithProperties() throws IOException { final String newName = "NewName"; HashMap properties = getBasicProperties(); CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, newName, @@ -160,7 +162,7 @@ public void testCopyNodeWithProperties() { } @Test - public void testCopyNodeReturnsAccesDenied() { + public void testCopyNodeReturnsAccesDenied() throws IOException { CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, null, null, null, copyFromFile); transactionService.getRetryingTransactionHelper() @@ -172,7 +174,7 @@ public void testCopyNodeReturnsAccesDenied() { } @Test - public void testCopyFolderInception() { + public void testCopyFolderInception() throws IOException { CreateNodeOptions createNodeOptions = getCreateNodeOptions(copyFromFolder, null, null, null, copyFromFolder); transactionService.getRetryingTransactionHelper() @@ -183,7 +185,7 @@ public void testCopyFolderInception() { } @Test - public void testCopyFolderTypeChange() { + public void testCopyFolderTypeChange() throws IOException { CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, null, c.apix(ContentModel.TYPE_CONTENT), null, copyFromFolder); transactionService.getRetryingTransactionHelper() @@ -194,7 +196,7 @@ public void testCopyFolderTypeChange() { } @Test - public void testCopyFolderSubTyping() { + public void testCopyFolderSubTyping() throws IOException { CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, null, c.apix(ContentModel.TYPE_DICTIONARY_MODEL), null, copyFromFile); transactionService.getRetryingTransactionHelper() @@ -205,7 +207,7 @@ public void testCopyFolderSubTyping() { } @Test - public void testMultipleCopies() { + public void testMultipleCopies() throws IOException { CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, null, null, null, copyFromFolder); for (int i = 0 ; i < 5 ; i++) { diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java index 3f7a7001..63e60544 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java @@ -3,6 +3,8 @@ import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.data.QName; + +import java.io.IOException; import java.util.HashMap; import eu.xenit.apix.rest.v1.nodes.CreateNodeOptions; import org.alfresco.model.ContentModel; @@ -37,7 +39,7 @@ public void setup() { } @Test - public void testCreateFile() { + public void testCreateFile() throws IOException { String name = "newFile"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(parentTestFolder, name, c.apix(ContentModel.TYPE_CONTENT), null, null); @@ -49,7 +51,7 @@ public void testCreateFile() { } @Test - public void testCreateFolder() { + public void testCreateFolder() throws IOException { String name = "newFolder"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(parentTestFolder, name, c.apix(ContentModel.TYPE_FOLDER), null, null); @@ -61,7 +63,7 @@ public void testCreateFolder() { } @Ignore - public void testCreateFileWithNoType() { + public void testCreateFileWithNoType() throws IOException { String name = "noType"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(parentTestFolder, name, null, null, null); @@ -74,7 +76,7 @@ public void testCreateFileWithNoType() { } @Test - public void testCreateFileWithProperties() { + public void testCreateFileWithProperties() throws IOException { String name = "newFile1"; HashMap properties = getBasicProperties(); CreateNodeOptions createNodeOptions = getCreateNodeOptions(parentTestFolder, name, @@ -87,7 +89,7 @@ public void testCreateFileWithProperties() { } @Test - public void testCreateFileDuplicateName() { + public void testCreateFileDuplicateName() throws IOException { String name = "duplicate"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(parentTestFolder, name, c.apix(ContentModel.TYPE_CONTENT), null, null); @@ -103,7 +105,7 @@ public void testCreateFileDuplicateName() { } @Test - public void testCreateNodeReturnsAccessDenied() { + public void testCreateNodeReturnsAccessDenied() throws IOException { String name = "Forbidden"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, name, c.apix(ContentModel.TYPE_CONTENT), null, null); diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/DictionaryTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/DictionaryTest.java index cfedcb1b..962d3980 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/DictionaryTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/DictionaryTest.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.net.URLEncoder; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import org.alfresco.repo.dictionary.DictionaryDAO; @@ -25,6 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.util.UriComponentsBuilder; public class DictionaryTest extends RestV1BaseTest { @@ -59,9 +61,12 @@ private void executeDictionaryTypeTest(String dictionaryType, String shortName, String baseUrl = makeAlfrescoBaseurlAdmin() + "/apix/v1/dictionary/" + dictionaryType + "/"; // Short qname lookup - HttpResponse httpResponse = Request.Get(baseUrl + shortName).execute().returnResponse(); + String uri = baseUrl + URLEncoder.encode(shortName, + String.valueOf(Charset.defaultCharset()) + ); + HttpResponse httpResponse = Request.Get(uri).execute().returnResponse(); logger.debug(EntityUtils.toString(httpResponse.getEntity())); - assertEquals(200, httpResponse.getStatusLine().getStatusCode()); + assertEquals(uri, 200, httpResponse.getStatusLine().getStatusCode()); JSONObject jsonObject = new JSONObject(EntityUtils.toString(httpResponse.getEntity())); assertEquals(longName, jsonObject.getString("name")); if (mandatoryAspect != null) { @@ -69,10 +74,12 @@ private void executeDictionaryTypeTest(String dictionaryType, String shortName, } // full qname lookup - httpResponse = Request.Get(baseUrl + URLEncoder.encode(longName, "utf-8").replaceAll("%2F", "/")).execute() - .returnResponse(); + String sanitizedLongQName = URLEncoder.encode(longName, + String.valueOf(Charset.defaultCharset())) + .replaceAll("%2F", "/"); + httpResponse = Request.Get(baseUrl + sanitizedLongQName).execute().returnResponse(); logger.debug(EntityUtils.toString(httpResponse.getEntity())); - assertEquals(200, httpResponse.getStatusLine().getStatusCode()); + assertEquals(sanitizedLongQName, 200, httpResponse.getStatusLine().getStatusCode()); jsonObject = new JSONObject(EntityUtils.toString(httpResponse.getEntity())); assertEquals(longName, jsonObject.getString("name")); @@ -89,7 +96,6 @@ public void testTypeDefinitionGet() throws IOException, JSONException { "{http://www.alfresco.org/model/content/1.0}auditable"); } - @Test public void testTypesGet() throws IOException, JSONException { String baseUrl = makeAlfrescoBaseurlAdmin() + "/apix/v1/dictionary/types"; diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/MetadataTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/MetadataTest.java index 0a7b6f6e..e251a7e6 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/MetadataTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/MetadataTest.java @@ -15,6 +15,7 @@ import org.apache.http.client.fluent.Request; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -109,7 +110,8 @@ public void testMetadataPost() throws IOException, JSONException { //Adding the cm:versionable aspect as a test httppost.setEntity(new StringEntity(json(String - .format("{'aspectsToAdd':['%s'], %s}", ContentModel.ASPECT_VERSIONABLE.toString(), propertiesToSet)))); + .format("{'aspectsToAdd':['%s'], %s}", ContentModel.ASPECT_VERSIONABLE.toString(), propertiesToSet)), + ContentType.APPLICATION_JSON)); final NodeRef testNodeRef; try (CloseableHttpResponse response = httpclient.execute(httppost)) { @@ -123,16 +125,13 @@ public void testMetadataPost() throws IOException, JSONException { } transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - org.alfresco.service.cmr.repository.NodeRef alfTestRef = new org.alfresco.service.cmr.repository.NodeRef( - testNodeRef.toString()); - assertEquals("newTitle", nodeService.getProperty(alfTestRef, ContentModel.PROP_TITLE)); - assertEquals(RestV1BaseTest.TESTFILE_NAME, nodeService.getProperty(alfTestRef, ContentModel.PROP_NAME)); - assertTrue(nodeService.hasAspect(alfTestRef, ContentModel.ASPECT_VERSIONABLE)); - return null; - } + .doInTransaction(() -> { + org.alfresco.service.cmr.repository.NodeRef alfTestRef = new org.alfresco.service.cmr.repository.NodeRef( + testNodeRef.toString()); + assertEquals("newTitle", nodeService.getProperty(alfTestRef, ContentModel.PROP_TITLE)); + assertEquals(RestV1BaseTest.TESTFILE_NAME, nodeService.getProperty(alfTestRef, ContentModel.PROP_NAME)); + assertTrue(nodeService.hasAspect(alfTestRef, ContentModel.ASPECT_VERSIONABLE)); + return null; }, false, true); } @@ -151,7 +150,8 @@ public void testMetadataPostReturnsAccesDenied() throws IOException, JSONExcepti //Adding the cm:versionable aspect as a test httppost.setEntity(new StringEntity(json(String - .format("{'aspectsToAdd':['%s'], %s}", ContentModel.ASPECT_VERSIONABLE.toString(), propertiesToSet)))); + .format("{'aspectsToAdd':['%s'], %s}", ContentModel.ASPECT_VERSIONABLE.toString(), propertiesToSet)), + ContentType.APPLICATION_JSON)); try (CloseableHttpResponse response = httpclient.execute(httppost)) { String jsonString = EntityUtils.toString(response.getEntity()); @@ -178,39 +178,38 @@ private boolean checkExists(NodeRef ref) { } @Test - public void testDeletePermanently() throws IOException { + public void testDeletePermanently() throws IOException, InterruptedException { final HashMap initializedNodeRefs = CreateAdminNode(); final String url = getUrl(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME)) + "?permanently=true"; + Request.Delete(url).execute().returnResponse(); + // Alfresco Cache is lagging behind... + Thread.sleep(2000); transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - Request.Delete(url).execute().returnResponse(); - org.alfresco.service.cmr.repository.NodeRef archivedRef = nodeArchiveService.getArchivedNode( - new org.alfresco.service.cmr.repository.NodeRef(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue())); - assertFalse(checkExists(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME))); - logger.debug(" deleted node: " + archivedRef.toString()); - assertNotNull(archivedRef); - return null; - } + .doInTransaction(() -> { + assertFalse(checkExists(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME))); + org.alfresco.service.cmr.repository.NodeRef archivedRef = nodeArchiveService.getArchivedNode( + new org.alfresco.service.cmr.repository.NodeRef(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue())); + logger.debug(" deleted node: {}", archivedRef); + assertNotNull(archivedRef); + return null; }, true, true); } @Test - public void testDeleteToArchive() throws IOException { + public void testDeleteToArchive() throws IOException, InterruptedException { final HashMap initializedNodeRefs = CreateAdminNode(); final String url = getUrl(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME)); + Request.Delete(url).execute().returnResponse(); + // Alfresco Cache is lagging behind... + Thread.sleep(2000); transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - Request.Delete(url).execute().returnResponse(); - assertFalse(checkExists(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME))); - org.alfresco.service.cmr.repository.NodeRef archivedRef = nodeArchiveService.getArchivedNode( - new org.alfresco.service.cmr.repository.NodeRef(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue())); - assertNotNull(archivedRef); - return null; - } + .doInTransaction(() -> { + assertFalse(checkExists(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME))); + org.alfresco.service.cmr.repository.NodeRef archivedRef = nodeArchiveService.getArchivedNode( + new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue())); + assertNotNull(archivedRef); + return null; }, true, true); } diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/MoveNodeTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/MoveNodeTest.java index a8304a81..2d332e46 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/MoveNodeTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/MoveNodeTest.java @@ -13,6 +13,7 @@ import org.alfresco.service.transaction.TransactionService; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -100,7 +101,8 @@ public void testMoveNodeReturnsAccesDenied() throws IOException { logger.debug(" URL: " + url); final CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPut httpPut = new HttpPut(url); - httpPut.setEntity(new StringEntity(String.format("{\"parent\":\"%s\"}", mainTestFolder.toString()))); + httpPut.setEntity(new StringEntity(String.format("{\"parent\":\"%s\"}", mainTestFolder.toString()), + ContentType.APPLICATION_JSON)); try(CloseableHttpResponse httpResponse = httpClient.execute(httpPut)) { assertEquals(403, httpResponse.getStatusLine().getStatusCode()); diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java index 541b364c..3a4f92de 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java @@ -3,14 +3,14 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import eu.xenit.apix.data.ContentInputStream; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.node.INodeService; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; + +import java.io.*; +import java.nio.charset.Charset; import java.util.HashMap; import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.transaction.TransactionService; import org.apache.commons.io.IOUtils; import org.apache.http.HttpEntity; @@ -18,25 +18,16 @@ import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPut; -import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -/** - * Created by kenneth on 17.03.16. - */ public class NodeContentTest extends RestV1BaseTest { - - private final static Logger logger = LoggerFactory.getLogger(NodeContentTest.class); - @Autowired INodeService nodeService; @@ -50,114 +41,106 @@ public void setup() { } @Test - public void testSetNodeContent() throws IOException { + public void testSetNodeContent() { final HashMap initializedNodeRefs = init(); - final String url = makeNodesUrl(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME), "/content", "admin", "admin"); + final String url = makeNodesUrl( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME), + "/content", "admin", "admin"); final CloseableHttpClient httpclient = HttpClients.createDefault(); - transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - HttpPut httpput = new HttpPut(url); - HttpEntity httpBody = MultipartEntityBuilder.create() - .addBinaryBody("file", "test content123".getBytes(), ContentType.TEXT_PLAIN, "abc.txt") - .build(); - httpput.setEntity(httpBody); - - try (CloseableHttpResponse response = httpclient.execute(httpput)) { - assertEquals(200, response.getStatusLine().getStatusCode()); - } - - return null; + int returnedStatusCode = transactionService.getRetryingTransactionHelper() + .doInTransaction(() -> { + HttpPut httpput = new HttpPut(url); + HttpEntity httpBody = MultipartEntityBuilder.create() + .addBinaryBody( + "file", createTestFile()) + .build(); + httpput.setEntity(httpBody); + + try (CloseableHttpResponse response = httpclient.execute(httpput)) { + return response.getStatusLine().getStatusCode(); } }, false, true); + assertEquals(200, returnedStatusCode); - transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - InputStream inputStream = nodeService - .getContent(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME)).getInputStream(); - assertEquals("test content123", IOUtils.toString(inputStream)); - inputStream.close(); - return null; + final INodeService ns = this.nodeService; + final NodeRef nodeRef = initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME); + String content = transactionService.getRetryingTransactionHelper() + .doInTransaction(() -> { + ContentInputStream c = ns.getContent(nodeRef); + try(InputStream inputStream = c.getInputStream()) { + return IOUtils.toString(inputStream, Charset.defaultCharset()); } }, false, true); - + assertEquals("This is the content", content); } @Test - public void testSetNodeContentReturnsAccesDenied() throws IOException { + public void testSetNodeContentReturnsAccessDenied() { final HashMap initializedNodeRefs = init(); - final String url = makeNodesUrl(initializedNodeRefs.get(RestV1BaseTest.NOUSERRIGHTS_FILE_NAME), "/content", RestV1BaseTest.USERWITHOUTRIGHTS, + final String url = makeNodesUrl( + initializedNodeRefs.get(RestV1BaseTest.NOUSERRIGHTS_FILE_NAME), + "/content", RestV1BaseTest.USERWITHOUTRIGHTS, RestV1BaseTest.USERWITHOUTRIGHTS); final CloseableHttpClient httpclient = HttpClients.createDefault(); - transactionService.getRetryingTransactionHelper() + int receivedStatusCode = transactionService.getRetryingTransactionHelper() .doInTransaction(() -> { HttpPut httpput = new HttpPut(url); HttpEntity httpBody = MultipartEntityBuilder.create() - .addBinaryBody("file", "test content123".getBytes(), ContentType.TEXT_PLAIN, "abc.txt") + .addBinaryBody( + "file", createTestFile()) .build(); httpput.setEntity(httpBody); try (CloseableHttpResponse response = httpclient.execute(httpput)) { - assertEquals(403, response.getStatusLine().getStatusCode()); + return response.getStatusLine().getStatusCode(); } - - return null; }, false, true); + assertEquals(403, receivedStatusCode); } @Test - public void testDeleteNodeContent() throws IOException { + public void testDeleteNodeContent() { final HashMap initializedNodeRefs = init(); - final String url = makeNodesUrl(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME), "/content", "admin", "admin"); + final String url = makeNodesUrl(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME), + "/content", "admin", "admin"); final CloseableHttpClient httpclient = HttpClients.createDefault(); transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - nodeService.setContent(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME), - new ByteArrayInputStream("test contentabc".getBytes()), - "abc.txt"); - return null; - } + .doInTransaction(() -> { + nodeService.setContent(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME), + new ByteArrayInputStream("test contentabc".getBytes()), + "abc.txt"); + return null; }, false, true); transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - HttpDelete httpDelete = new HttpDelete(url); - - try (CloseableHttpResponse response = httpclient.execute(httpDelete)) { - assertEquals(200, response.getStatusLine().getStatusCode()); - } - return null; + .doInTransaction(() -> { + HttpDelete httpDelete = new HttpDelete(url); + + try (CloseableHttpResponse response = httpclient.execute(httpDelete)) { + assertEquals(200, response.getStatusLine().getStatusCode()); } + return null; }, false, true); transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - - assertNull(nodeService.getContent(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME))); - return null; - } + .doInTransaction(() -> { + assertNull(nodeService.getContent(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME))); + return null; }, false, true); } @Test - public void testDeleteNodeContentReturnsAccesDenied() throws IOException { + public void testDeleteNodeContentReturnsAccesDenied() { final HashMap initializedNodeRefs = init(); - final String url = makeNodesUrl(initializedNodeRefs.get(RestV1BaseTest.NOUSERRIGHTS_FILE_NAME), "/content", RestV1BaseTest.USERWITHOUTRIGHTS, + final String url = makeNodesUrl( + initializedNodeRefs.get(RestV1BaseTest.NOUSERRIGHTS_FILE_NAME), + "/content", RestV1BaseTest.USERWITHOUTRIGHTS, RestV1BaseTest.USERWITHOUTRIGHTS); final CloseableHttpClient httpclient = HttpClients.createDefault(); @@ -171,44 +154,43 @@ public void testDeleteNodeContentReturnsAccesDenied() throws IOException { } @Test - public void testGetNodeContent() throws IOException { + public void testGetNodeContent() { final HashMap initializedNodeRefs = init(); - final String url = makeNodesUrl(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME), "/content", "admin", "admin"); + final String url = makeNodesUrl( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME), + "/content", "admin", "admin"); final CloseableHttpClient httpclient = HttpClients.createDefault(); + final INodeService ns = this.nodeService; transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - nodeService.setContent(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME), - new ByteArrayInputStream("test contentdef".getBytes()), - "abc.txt"); - return null; - } + .doInTransaction(() -> { + ns.setContent(initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME), + new ByteArrayInputStream("test contentdef".getBytes()), + "abc.txt"); + return null; }, false, true); transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - HttpGet httpGet = new HttpGet(url); - - try (CloseableHttpResponse response = httpclient.execute(httpGet)) { - assertEquals(200, response.getStatusLine().getStatusCode()); - InputStream inputStream = response.getEntity().getContent(); - assertEquals("test contentdef", IOUtils.toString(inputStream)); - inputStream.close(); - } - return null; + .doInTransaction(() -> { + HttpGet httpGet = new HttpGet(url); + + try (CloseableHttpResponse response = httpclient.execute(httpGet)) { + assertEquals(200, response.getStatusLine().getStatusCode()); + InputStream inputStream = response.getEntity().getContent(); + assertEquals("test contentdef", + IOUtils.toString(inputStream, Charset.defaultCharset())); + inputStream.close(); } + return null; }, false, true); } @Test - public void testGetNodeContentReturnsAccesDenied() throws IOException { + public void testGetNodeContentReturnsAccesDenied() { final HashMap initializedNodeRefs = init(); - final String url = makeNodesUrl(initializedNodeRefs.get(RestV1BaseTest.NOUSERRIGHTS_FILE_NAME), "/content", RestV1BaseTest.USERWITHOUTRIGHTS, + final String url = makeNodesUrl(initializedNodeRefs.get(RestV1BaseTest.NOUSERRIGHTS_FILE_NAME), + "/content", RestV1BaseTest.USERWITHOUTRIGHTS, RestV1BaseTest.USERWITHOUTRIGHTS); final CloseableHttpClient httpclient = HttpClients.createDefault(); @@ -221,6 +203,17 @@ public void testGetNodeContentReturnsAccesDenied() throws IOException { }, false, true); } + private File createTestFile() throws IOException { + String pathName = "test.txt"; + File result = new File(pathName); + result.createNewFile(); + PrintWriter writer = new PrintWriter(pathName, "UTF-8"); + String contentString = "This is the content"; + writer.print(contentString); + writer.close(); + return result; + } + @After public void cleanUp() { this.removeMainTestFolder(); diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java index 180b4e98..4d0b2c0a 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java @@ -23,6 +23,7 @@ import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -69,7 +70,7 @@ public eu.xenit.apix.data.NodeRef doPostNodes(CreateNodeOptions createNodeOption //deserialization failed HttpEntityEnclosingRequestBase req = new HttpPost(url); final CloseableHttpClient checkoutHttpclient = HttpClients.createDefault(); - req.setEntity(new StringEntity(requestBody)); + req.setEntity(new StringEntity(requestBody, ContentType.APPLICATION_JSON)); try (CloseableHttpResponse response = checkoutHttpclient.execute(req)) { String result = EntityUtils.toString(response.getEntity()); assertEquals(expectedResponseCode, response.getStatusLine().getStatusCode()); @@ -87,22 +88,17 @@ public eu.xenit.apix.data.NodeRef doPostNodes(CreateNodeOptions createNodeOption protected CreateNodeOptions getCreateNodeOptions(eu.xenit.apix.data.NodeRef parentRef, String name, eu.xenit.apix.data.QName type, HashMap properties, QName[] aspectsToAdd, - QName[] aspectsToRemove, eu.xenit.apix.data.NodeRef copyFrom) { + QName[] aspectsToRemove, eu.xenit.apix.data.NodeRef copyFrom) throws IOException { String parentRefString = (parentRef != null) ? parentRef.toString() : null; String copyFromString = (copyFrom != null) ? copyFrom.toString() : null; String typeString = (type != null) ? type.toString() : null; - try { - return new CreateNodeOptions(parentRefString, name, typeString, properties, aspectsToAdd, aspectsToRemove, copyFromString); - } catch (IOException e) { - e.printStackTrace(); - } - return null; + return new CreateNodeOptions(parentRefString, name, typeString, properties, aspectsToAdd, aspectsToRemove, copyFromString); } protected CreateNodeOptions getCreateNodeOptions(eu.xenit.apix.data.NodeRef parentRef, String name, eu.xenit.apix.data.QName type, HashMap properties, - eu.xenit.apix.data.NodeRef copyFrom) { + eu.xenit.apix.data.NodeRef copyFrom) throws IOException { return getCreateNodeOptions(parentRef, name, type, properties, null, null, copyFrom); } diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/PermissionsTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/PermissionsTest.java index 0ed0b5ae..077e49a9 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/PermissionsTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/PermissionsTest.java @@ -10,6 +10,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.apache.http.HttpResponse; import org.apache.http.client.fluent.Request; +import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.util.EntityUtils; import org.json.JSONArray; @@ -179,7 +180,8 @@ public void testSetNodeAclsReturnsAccesDenied() throws IOException { + " \"permission\": \"Collaborator\"\n" + " }\n" + "]}" - )).execute().returnResponse(); + , + ContentType.APPLICATION_JSON)).execute().returnResponse(); logger.debug(EntityUtils.toString(httpResponse.getEntity())); String result = EntityUtils.toString(httpResponse.getEntity()); assertEquals(403, httpResponse.getStatusLine().getStatusCode()); @@ -192,7 +194,8 @@ public void testSetInheritFromParentReturnsAccesDenied() throws IOException { Request.Post( makeNodesUrl(initializedNodeRefs.get(RestV1BaseTest.NOUSERRIGHTS_FILE_NAME), "/acl/inheritFromParent", RestV1BaseTest.USERWITHOUTRIGHTS, RestV1BaseTest.USERWITHOUTRIGHTS)) - .body(new StringEntity("{\"inheritFromParent\":true}")) + .body(new StringEntity("{\"inheritFromParent\":true}", + ContentType.APPLICATION_JSON)) .execute() .returnResponse() .getStatusLine() diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/RestV1BaseTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/RestV1BaseTest.java index 6eebef33..645bf430 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/RestV1BaseTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/RestV1BaseTest.java @@ -36,6 +36,7 @@ import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -202,53 +203,56 @@ protected String makeCommentsUrl(eu.xenit.apix.data.NodeRef nodeRef, String user } protected HashMap init() { + return init(null); + } + + protected HashMap init(final String testName) { final HashMap initializedNodeRefs = new HashMap<>(); TransactionService transactionService = serviceRegistry.getTransactionService(); this.removeMainTestFolder(); - RetryingTransactionHelper.RetryingTransactionCallback txnWork = new RetryingTransactionHelper.RetryingTransactionCallback() { - public Object execute() throws Exception { - NodeRef companyHomeRef = repository.getCompanyHome(); - FileInfo mainTestFolder = createTestNode(companyHomeRef, MAIN_TESTFOLDER_NAME, - ContentModel.TYPE_FOLDER); - FileInfo testFolder = createTestNode(mainTestFolder.getNodeRef(), TESTFOLDER_NAME, - ContentModel.TYPE_FOLDER); - initializedNodeRefs.put(TESTFOLDER_NAME, new eu.xenit.apix.data.NodeRef(testFolder.getNodeRef().toString())); - FileInfo testNode = createTestNode(testFolder.getNodeRef(), TESTFILE_NAME, ContentModel.TYPE_CONTENT); - NodeRef testNodeRef = testNode.getNodeRef(); - eu.xenit.apix.data.NodeRef apixTestNodeRef = new eu.xenit.apix.data.NodeRef(testNodeRef.toString()); - initializedNodeRefs.put(TESTFILE_NAME, apixTestNodeRef); - - FileInfo testFolder2 = createTestNode(mainTestFolder.getNodeRef(), TESTFOLDER2_NAME, - ContentModel.TYPE_FOLDER); - FileInfo testNode2 = createTestNode(testFolder2.getNodeRef(), TESTFILE2_NAME, - ContentModel.TYPE_CONTENT); - NodeRef testNodeRef2 = testNode2.getNodeRef(); - eu.xenit.apix.data.NodeRef apixTestNodeRef2 = new eu.xenit.apix.data.NodeRef(testNodeRef2.toString()); - initializedNodeRefs.put(TESTFILE2_NAME, apixTestNodeRef2); - - FileInfo testNode3 = createTestNode(testFolder2.getNodeRef(), TESTFILE3_NAME, - ContentModel.TYPE_CONTENT); - NodeRef testNodeRef3 = testNode3.getNodeRef(); - eu.xenit.apix.data.NodeRef apixTestNodeRef3 = new eu.xenit.apix.data.NodeRef(testNodeRef3.toString()); - initializedNodeRefs.put(TESTFILE3_NAME, apixTestNodeRef3); - - FileInfo noUserRightsFolder = createTestNode(mainTestFolder.getNodeRef(), NOUSERRIGHTS_FOLDER_NAME, - ContentModel.TYPE_FOLDER); - setPermissionInheritance(noUserRightsFolder.getNodeRef(), false); - FileInfo noUserRightsNode = createTestNode(noUserRightsFolder.getNodeRef(), NOUSERRIGHTS_FILE_NAME, - ContentModel.TYPE_CONTENT); - NodeRef noUserRightsNodeRef = noUserRightsNode.getNodeRef(); - setPermissionInheritance(noUserRightsNodeRef, false); - eu.xenit.apix.data.NodeRef apixNoUserRightsNodeRef = new eu.xenit.apix.data.NodeRef( - noUserRightsNodeRef.toString()); - initializedNodeRefs.put(NOUSERRIGHTS_FILE_NAME, apixNoUserRightsNodeRef); - - createUser(USERWITHOUTRIGHTS, USERWITHOUTRIGHTS, USERWITHOUTRIGHTS, - USERWITHOUTRIGHTS_EMAIL); - return null; - } + RetryingTransactionHelper.RetryingTransactionCallback txnWork = () -> { + String mainTestFolderName = MAIN_TESTFOLDER_NAME + (testName != null ? "_" + testName : ""); + NodeRef companyHomeRef = repository.getCompanyHome(); + FileInfo mainTestFolder = createTestNode(companyHomeRef, mainTestFolderName, + ContentModel.TYPE_FOLDER); + FileInfo testFolder = createTestNode(mainTestFolder.getNodeRef(), TESTFOLDER_NAME, + ContentModel.TYPE_FOLDER); + initializedNodeRefs.put(TESTFOLDER_NAME, new eu.xenit.apix.data.NodeRef(testFolder.getNodeRef().toString())); + FileInfo testNode = createTestNode(testFolder.getNodeRef(), TESTFILE_NAME, ContentModel.TYPE_CONTENT); + NodeRef testNodeRef = testNode.getNodeRef(); + eu.xenit.apix.data.NodeRef apixTestNodeRef = new eu.xenit.apix.data.NodeRef(testNodeRef.toString()); + initializedNodeRefs.put(TESTFILE_NAME, apixTestNodeRef); + + FileInfo testFolder2 = createTestNode(mainTestFolder.getNodeRef(), TESTFOLDER2_NAME, + ContentModel.TYPE_FOLDER); + FileInfo testNode2 = createTestNode(testFolder2.getNodeRef(), TESTFILE2_NAME, + ContentModel.TYPE_CONTENT); + NodeRef testNodeRef2 = testNode2.getNodeRef(); + eu.xenit.apix.data.NodeRef apixTestNodeRef2 = new eu.xenit.apix.data.NodeRef(testNodeRef2.toString()); + initializedNodeRefs.put(TESTFILE2_NAME, apixTestNodeRef2); + + FileInfo testNode3 = createTestNode(testFolder2.getNodeRef(), TESTFILE3_NAME, + ContentModel.TYPE_CONTENT); + NodeRef testNodeRef3 = testNode3.getNodeRef(); + eu.xenit.apix.data.NodeRef apixTestNodeRef3 = new eu.xenit.apix.data.NodeRef(testNodeRef3.toString()); + initializedNodeRefs.put(TESTFILE3_NAME, apixTestNodeRef3); + + FileInfo noUserRightsFolder = createTestNode(mainTestFolder.getNodeRef(), NOUSERRIGHTS_FOLDER_NAME, + ContentModel.TYPE_FOLDER); + setPermissionInheritance(noUserRightsFolder.getNodeRef(), false); + FileInfo noUserRightsNode = createTestNode(noUserRightsFolder.getNodeRef(), NOUSERRIGHTS_FILE_NAME, + ContentModel.TYPE_CONTENT); + NodeRef noUserRightsNodeRef = noUserRightsNode.getNodeRef(); + setPermissionInheritance(noUserRightsNodeRef, false); + eu.xenit.apix.data.NodeRef apixNoUserRightsNodeRef = new eu.xenit.apix.data.NodeRef( + noUserRightsNodeRef.toString()); + initializedNodeRefs.put(NOUSERRIGHTS_FILE_NAME, apixNoUserRightsNodeRef); + + createUser(USERWITHOUTRIGHTS, USERWITHOUTRIGHTS, USERWITHOUTRIGHTS, + USERWITHOUTRIGHTS_EMAIL); + return null; }; transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, false, true); @@ -400,7 +404,7 @@ private T doWithBody(HttpEntityEnclosingRequestBase req, Class returnType final CloseableHttpClient checkoutHttpclient = HttpClients.createDefault(); if (jsonBody != null) { String checkoutJsonString = json(String.format(jsonBody, args)); - req.setEntity(new StringEntity(checkoutJsonString)); + req.setEntity(new StringEntity(checkoutJsonString, ContentType.APPLICATION_JSON)); } try (CloseableHttpResponse response = checkoutHttpclient.execute(req)) { diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java index 62b09d4a..b149571a 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java @@ -66,25 +66,22 @@ public void testGetVersionHistorySimpleNode() throws IOException { final HashMap initializedNodeRefs = init(); final String[] url = new String[1]; transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - NodeRef testNode = initializedNodeRefs.get(RestV1BaseTest.TESTFILE3_NAME); - url[0] = createApixUrl("/versionhistory/%s/%s/%s/versions", testNode.getStoreRefProtocol(), - testNode.getStoreRefId(), testNode.getGuid()); - HashMap versionProperties = new HashMap<>(); - versionProperties.put(VersionBaseModel.PROP_VERSION_TYPE, - org.alfresco.service.cmr.version.VersionType.MAJOR); - versionProperties.put(VersionBaseModel.PROP_DESCRIPTION, "Test123"); - org.alfresco.service.cmr.version.Version version = alfrizcoVersionHistoryService - .createVersion(c.alfresco(testNode), versionProperties); - logger.debug(" versioning 1 label: " + version.getVersionLabel()); - versionProperties.put(VersionBaseModel.PROP_DESCRIPTION, "Test456"); - org.alfresco.service.cmr.version.Version version2 = alfrizcoVersionHistoryService - .createVersion(c.alfresco(testNode), versionProperties); - logger.debug(" versioning 2 label: " + version2.getVersionLabel()); - return null; - } + .doInTransaction(() -> { + NodeRef testNode = initializedNodeRefs.get(RestV1BaseTest.TESTFILE3_NAME); + url[0] = createApixUrl("/versionhistory/%s/%s/%s/versions", testNode.getStoreRefProtocol(), + testNode.getStoreRefId(), testNode.getGuid()); + HashMap versionProperties = new HashMap<>(); + versionProperties.put(VersionBaseModel.PROP_VERSION_TYPE, + org.alfresco.service.cmr.version.VersionType.MAJOR); + versionProperties.put(VersionBaseModel.PROP_DESCRIPTION, "Test123"); + org.alfresco.service.cmr.version.Version version = alfrizcoVersionHistoryService + .createVersion(c.alfresco(testNode), versionProperties); + logger.debug(" versioning 1 label: " + version.getVersionLabel()); + versionProperties.put(VersionBaseModel.PROP_DESCRIPTION, "Test456"); + org.alfresco.service.cmr.version.Version version2 = alfrizcoVersionHistoryService + .createVersion(c.alfresco(testNode), versionProperties); + logger.debug(" versioning 2 label: " + version2.getVersionLabel()); + return null; }, false, true); HttpResponse httpResponse = Request.Get(url[0]).execute().returnResponse(); @@ -115,13 +112,11 @@ public void testSetVersionHistoryWithoutBody() throws IOException { initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getStoreRefId(), initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getGuid()); transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - public Object execute() throws Throwable { - assertFalse(versionService - .isVersioned(new org.alfresco.service.cmr.repository.NodeRef( - initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue()))); - return null; - } + .doInTransaction(() -> { + assertFalse(versionService + .isVersioned(new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue()))); + return null; }, true, true); int statusCode = Request.Put(versionHistoryUrl) @@ -132,39 +127,35 @@ public Object execute() throws Throwable { assertEquals(200, statusCode); transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - public Object execute() throws Throwable { - assertTrue(alfrizcoVersionHistoryService - .isVersioned(new org.alfresco.service.cmr.repository.NodeRef( - initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue()))); - assertEquals(defaultAutoVersion, nodeService - .getProperty(new org.alfresco.service.cmr.repository.NodeRef( - initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue()), - ContentModel.PROP_AUTO_VERSION)); - assertEquals(defaultAutoVersionProps, nodeService - .getProperty(new org.alfresco.service.cmr.repository.NodeRef( - initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue()), - ContentModel.PROP_AUTO_VERSION_PROPS)); - assertEquals(defaultInitialVersion, nodeService - .getProperty(new org.alfresco.service.cmr.repository.NodeRef( - initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue()), - ContentModel.PROP_INITIAL_VERSION)); - assertEquals("1.0", nodeService - .getProperty(new org.alfresco.service.cmr.repository.NodeRef( - initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue()), - ContentModel.PROP_VERSION_LABEL)); - return null; - } + .doInTransaction(() -> { + assertTrue(alfrizcoVersionHistoryService + .isVersioned(new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue()))); + assertEquals(defaultAutoVersion, nodeService + .getProperty(new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue()), + ContentModel.PROP_AUTO_VERSION)); + assertEquals(defaultAutoVersionProps, nodeService + .getProperty(new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue()), + ContentModel.PROP_AUTO_VERSION_PROPS)); + assertEquals(defaultInitialVersion, nodeService + .getProperty(new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue()), + ContentModel.PROP_INITIAL_VERSION)); + assertEquals("1.0", nodeService + .getProperty(new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME).getValue()), + ContentModel.PROP_VERSION_LABEL)); + return null; }, true, true); transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - public Object execute() throws Throwable { - assertFalse(alfrizcoVersionHistoryService - .isVersioned(new org.alfresco.service.cmr.repository.NodeRef( - initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME).getValue()))); - return null; - } + .doInTransaction(() -> { + assertFalse(alfrizcoVersionHistoryService + .isVersioned(new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME).getValue()))); + return null; }, true, true); String versionHistoryUrl2 = createApixUrl("/versionhistory/%s/%s/%s", @@ -187,29 +178,27 @@ public Object execute() throws Throwable { assertEquals(200, statusCode2); transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - public Object execute() throws Throwable { - assertTrue(alfrizcoVersionHistoryService - .isVersioned(new org.alfresco.service.cmr.repository.NodeRef( - initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME).getValue()))); - assertEquals(false, nodeService - .getProperty(new org.alfresco.service.cmr.repository.NodeRef( - initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME).getValue()), - ContentModel.PROP_AUTO_VERSION)); - assertEquals(true, nodeService - .getProperty(new org.alfresco.service.cmr.repository.NodeRef( - initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME).getValue()), - ContentModel.PROP_AUTO_VERSION_PROPS)); - assertEquals(false, nodeService - .getProperty(new org.alfresco.service.cmr.repository.NodeRef( - initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME).getValue()), - ContentModel.PROP_INITIAL_VERSION)); - assertEquals("1.0", nodeService - .getProperty(new org.alfresco.service.cmr.repository.NodeRef( - initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME).getValue()), - ContentModel.PROP_VERSION_LABEL)); - return null; - } + .doInTransaction(() -> { + assertTrue(alfrizcoVersionHistoryService + .isVersioned(new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME).getValue()))); + assertEquals(false, nodeService + .getProperty(new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME).getValue()), + ContentModel.PROP_AUTO_VERSION)); + assertEquals(true, nodeService + .getProperty(new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME).getValue()), + ContentModel.PROP_AUTO_VERSION_PROPS)); + assertEquals(false, nodeService + .getProperty(new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME).getValue()), + ContentModel.PROP_INITIAL_VERSION)); + assertEquals("1.0", nodeService + .getProperty(new org.alfresco.service.cmr.repository.NodeRef( + initializedNodeRefs.get(RestV1BaseTest.TESTFILE2_NAME).getValue()), + ContentModel.PROP_VERSION_LABEL)); + return null; }, true, true); } diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/temp/UploadFileTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/temp/UploadFileTest.java index 504c9d82..c518e137 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/temp/UploadFileTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/temp/UploadFileTest.java @@ -1,26 +1,15 @@ package eu.xenit.apix.rest.v1.tests.temp; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Before; import eu.xenit.apix.data.NodeRef; -import eu.xenit.apix.node.INodeService; import eu.xenit.apix.rest.v1.tests.RestV1BaseTest; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.PrintWriter; -import java.net.URL; import java.util.Map; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.service.ServiceRegistry; -import org.alfresco.service.cmr.repository.ContentService; -import org.alfresco.service.cmr.repository.NodeService; -import org.apache.commons.io.IOUtils; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; @@ -29,37 +18,21 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; -import org.json.JSONArray; import org.json.JSONException; -import org.json.JSONObject; +import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - public class UploadFileTest extends RestV1BaseTest { - private final static Logger logger = LoggerFactory.getLogger(UploadFileTest.class); + private static final Logger logger = LoggerFactory.getLogger(UploadFileTest.class); private static final String LOCAL_TESTFILE_NAME = "test.txt"; - - @Autowired - ServiceRegistry serviceRegistry; - - @Autowired - INodeService nodeService; - private RetryingTransactionHelper transactionHelper; - private NodeService alfrescoNodeService; - private ContentService contentService; private NodeRef parentNodeRef; private Map initNodeRefArray; @org.junit.Before public void setUp() { - transactionHelper = this.serviceRegistry.getRetryingTransactionHelper(); - alfrescoNodeService = this.serviceRegistry.getNodeService(); - contentService = this.serviceRegistry.getContentService(); - initNodeRefArray = init(); this.parentNodeRef = initNodeRefArray.get(RestV1BaseTest.TESTFOLDER_NAME); } @@ -93,11 +66,11 @@ public void testUploadFileWhereFileAlreadyExists() throws IOException { @Test public void testUploadFileResultsInAccessDenied() throws IOException { String url = createUrl(RestV1BaseTest.USERWITHOUTRIGHTS, RestV1BaseTest.USERWITHOUTRIGHTS); - logger.debug(">>>>> URL: " + url); + logger.debug(">>>>> URL: {}", url); HttpEntity entity = createHttpEntity(initNodeRefArray.get(RestV1BaseTest.NOUSERRIGHTS_FILE_NAME).toString(), LOCAL_TESTFILE_NAME); try (CloseableHttpResponse response = doPost(url, entity)) { String resultString = EntityUtils.toString(response.getEntity()); - logger.debug(" resultString: " + resultString); + logger.debug(" resultString: {}", resultString); assertEquals(403, response.getStatusLine().getStatusCode()); } } @@ -112,44 +85,44 @@ private String createUrl(String username, String password) { return urlBuilder.toString(); } - private HttpEntity createHttpEntity(String parentRef, String filename) throws IOException { - return MultipartEntityBuilder.create() - .addTextBody("parent", parentRef) - .addTextBody("type", ContentModel.TYPE_CONTENT.toString()) - .addBinaryBody("file", createTestFile(filename)) - .build(); - } - - private CloseableHttpResponse doPost(String url, HttpEntity entity) throws IOException { - CloseableHttpClient httpClient = HttpClients.createDefault(); - HttpPost httpPost = new HttpPost(url); - httpPost.setEntity(entity); - return httpClient.execute(httpPost); - } - @Test - /** Upload a file and simulteanously set its metadata. */ + /* Upload a file and simultaneously set its metadata. */ public void testUploadFileWithMetadata() throws IOException, JSONException { - String property_name = "{http://www.alfresco.org/model/content/1.0}title"; - String property_value = "Saifutsuhengoshiatsuken"; - String metadata = String.format("{ 'propertiesToSet': { '%s': ['%s'] }}", property_name, property_value); + String propertyName = "{http://www.alfresco.org/model/content/1.0}title"; + String propertyValue = "Saifutsuhengoshiatsuken"; + String metadata = String.format("{ 'propertiesToSet': { '%s': ['%s'] }}", propertyName, propertyValue); HttpEntity entity = MultipartEntityBuilder.create() - .addTextBody("parent", this.parentNodeRef.toString()) - .addTextBody("type", ContentModel.TYPE_CONTENT.toString()) + .addTextBody("parent", this.parentNodeRef.toString(), ContentType.TEXT_PLAIN) + .addTextBody("type", ContentModel.TYPE_CONTENT.toString(), ContentType.TEXT_PLAIN) .addBinaryBody("file", createTestFile(LOCAL_TESTFILE_NAME)) - .addTextBody("metadata", json(metadata)) + .addTextBody("metadata", json(metadata), ContentType.APPLICATION_JSON) .build(); CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(makeAlfrescoBaseurlAdmin() + "/apix/v1/nodes/upload"); httpPost.setEntity(entity); try (CloseableHttpResponse response = httpClient.execute(httpPost)) { - String resultString = EntityUtils.toString(response.getEntity()); + EntityUtils.toString(response.getEntity()); assertEquals(200, response.getStatusLine().getStatusCode()); } } + private HttpEntity createHttpEntity(String parentRef, String filename) throws IOException { + return MultipartEntityBuilder.create() + .addTextBody("parent", parentRef) + .addTextBody("type", ContentModel.TYPE_CONTENT.toString()) + .addBinaryBody("file", createTestFile(filename)) + .build(); + } + + private CloseableHttpResponse doPost(String url, HttpEntity entity) throws IOException { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpPost httpPost = new HttpPost(url); + httpPost.setEntity(entity); + return httpClient.execute(httpPost); + } + private File createTestFile(String pathName) throws IOException { File result = new File(pathName); @@ -166,31 +139,4 @@ private File createTestFile(String pathName) throws IOException { writer.close(); return result; } - - private File createTempMail() throws IOException { - ClassLoader classLoader = getClass().getClassLoader(); - logger.debug("ClassLoader classLoader = getClass().getClassLoader()"); - URL mail = classLoader.getResource("cyrillic_message.msg"); - logger.debug("Email: " + mail.getPath()); - InputStream inputStream = mail.openStream(); - logger.debug("Input stream is available:" + inputStream.available()); - logger.debug("InputStream inputStream = classLoader.getResourceAsStream(\"cyrillic_message.msg\")"); - - File tempFile = File.createTempFile("test", "msg"); - logger.debug("File tempFile = File.createTempFile(\"test\", \"msg\");"); - logger.debug("tempFile name: " + tempFile.getName()); - tempFile.deleteOnExit(); - logger.debug("tempFile.deleteOnExit()"); - FileOutputStream out = new FileOutputStream(tempFile); - logger.debug("FileOutputStream out = new FileOutputStream(tempFile);"); - IOUtils.copy(inputStream, out); - logger.debug("Copied content to tempFile"); - - out.flush(); - out.close(); - inputStream.close(); - - logger.debug("Flushed and closed input and output streams."); - return tempFile; - } } diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/temp/V1SearchWebscriptTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/temp/V1SearchWebscriptTest.java index b9df68c1..57a0f357 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/temp/V1SearchWebscriptTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/temp/V1SearchWebscriptTest.java @@ -6,6 +6,7 @@ import java.io.IOException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -35,7 +36,7 @@ public void testSearch() throws IOException { " 'facets': { 'enabled': true } \n" + "}"); - checkoutHttppost.setEntity(new StringEntity(checkoutJsonString)); + checkoutHttppost.setEntity(new StringEntity(checkoutJsonString, ContentType.APPLICATION_JSON)); CloseableHttpResponse response = checkoutHttpclient.execute(checkoutHttppost); if (500 == response.getStatusLine().getStatusCode()) { diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java index 4eb87f30..ca8cf569 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java @@ -9,6 +9,7 @@ import org.apache.http.client.fluent.Request; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -67,7 +68,7 @@ public void testGetAllNodeInfoOfMultipleNodes() throws IOException, JSONExceptio final String url = makeAlfrescoBaseurl("admin", "admin") + "/apix/v2/nodes/nodeInfo"; logger.debug("url: " + url); HttpPost httppost = new HttpPost(url); - httppost.setEntity(new StringEntity(jsonString)); + httppost.setEntity(new StringEntity(jsonString, ContentType.APPLICATION_JSON)); try (CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(200, response.getStatusLine().getStatusCode()); @@ -85,7 +86,7 @@ public void testGetAllNodeInfoWithNoNodesListed() throws IOException { final String url = makeAlfrescoBaseurl("admin", "admin") + "/apix/v2/nodes/nodeInfo"; logger.debug("url: " + url); HttpPost httppost = new HttpPost(url); - httppost.setEntity(new StringEntity(jsonString)); + httppost.setEntity(new StringEntity(jsonString, ContentType.APPLICATION_JSON)); try (CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(400, response.getStatusLine().getStatusCode()); @@ -106,7 +107,7 @@ public void testGetAllNodeInfoForNodeWithoutPermissions() throws IOException { "]}"); final CloseableHttpClient httpclient = HttpClients.createDefault(); HttpPost httppost = new HttpPost(url); - httppost.setEntity(new StringEntity(jsonString)); + httppost.setEntity(new StringEntity(jsonString, ContentType.APPLICATION_JSON)); try (CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(200, response.getStatusLine().getStatusCode()); @@ -133,7 +134,7 @@ public void testGetAllNodeInfoWithoutNodeWithoutPermissions() throws IOException RestV1BaseTest.USERWITHOUTRIGHTS, RestV1BaseTest.USERWITHOUTRIGHTS) + "/apix/v1/nodes/nodeInfo"; logger.debug("url: " + url); HttpPost httppost = new HttpPost(url); - httppost.setEntity(new StringEntity(jsonString)); + httppost.setEntity(new StringEntity(jsonString, ContentType.APPLICATION_JSON)); try (CloseableHttpResponse response = httpclient.execute(httppost)) { assertEquals(200, response.getStatusLine().getStatusCode()); diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceFacetsTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceFacetsTest.java index e70dbc73..fb44832e 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceFacetsTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceFacetsTest.java @@ -20,8 +20,6 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; /** @@ -31,7 +29,6 @@ */ public class SearchServiceFacetsTest extends SearchServiceTest { - private final static Logger logger = LoggerFactory.getLogger(SearchServiceFacetsTest.class); private static final String ADMIN_USER_NAME = "admin"; @Autowired @@ -162,7 +159,7 @@ public void TestGetBucketedFacets() throws InterruptedException { query.setFacets(options); SearchQueryResult result = searchService.query(query); - // Search in results (Because of alf 4.2 source language level is 1.7. No lambdas to make this pretty 🙁) + // Search in results (Because of alf 4.2 source language level is 1.7. No lambdas to make this pretty) for (FacetSearchResult facetResult : result.getFacets()) { String facetName = facetResult.getName(); if (bucketedFacetNames.contains(facetName)) { diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceTest.java index 03603f73..fa2895e3 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceTest.java @@ -11,7 +11,6 @@ import eu.xenit.apix.search.SearchQueryResult; import eu.xenit.apix.search.nodes.SearchSyntaxNode; import eu.xenit.apix.tests.BaseTest; -import eu.xenit.apix.util.SolrTestHelperImpl; import java.io.IOException; import java.io.Serializable; import java.math.BigInteger; @@ -64,8 +63,6 @@ abstract public class SearchServiceTest extends BaseTest { @Autowired NamespacePrefixResolver namespacePrefixResolver; - protected SolrTestHelperImpl solrTestHelper; - final protected static String APIXTEST_NS = "http://test.apix.xenit.eu/model/content"; final protected static QName APIXTEST_LANGUAGE = QName.createQName(APIXTEST_NS, "language"); final protected static QName APIXTEST_DOCUMENT_STATUS = QName.createQName(APIXTEST_NS, "documentStatus"); diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/TermHitHighlightingTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/TermHitHighlightingTest.java index 8888a2f6..45a0984b 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/TermHitHighlightingTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/TermHitHighlightingTest.java @@ -33,16 +33,12 @@ @Ignore("Disabled for GHA build") public class TermHitHighlightingTest extends BaseTest { - private static final Logger log = LoggerFactory.getLogger(TermHitHighlightingTest.class); - @Autowired INodeService nodeService; @Autowired SearchService searchService; @Autowired RetryingTransactionHelper retryingTransactionHelper; - - private ObjectMapper mapper = new ObjectMapper(); private static final String FURIES_TXT = "" + "The furies are at home\nin the mirror; it is their address.\nEven the clearest water,\nif deep enough can drown.\n" + "\nNever think to surprise them.\nYour face approaching ever\nso friendly is the white flag\nthey ignore. There is no truce\n" @@ -72,7 +68,7 @@ public void cleanupAfterHighlightTest() { @Test /** Test all major parameters for term hit highlighting */ - public void searchResponseContainsHighlights() throws IOException, InterruptedException { + public void searchResponseContainsHighlights() throws InterruptedException { int initialCleanDocs = solrHelper.getNumberOfFtsStatusCleanDocs(); List expected = Arrays.asList(new HighlightResult("cm:content", Arrays.asList("" + "The !PREFIX!furies!SUFFIX! are at home\nin the mirror; it is their address.\n" diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/WorkflowServiceBaseTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/WorkflowServiceBaseTest.java index 9ef11a5d..3be13881 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/WorkflowServiceBaseTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/WorkflowServiceBaseTest.java @@ -23,10 +23,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import java.io.Serializable; import java.util.*; + public abstract class WorkflowServiceBaseTest extends BaseTest { protected final static Logger logger = LoggerFactory.getLogger(WorkflowServiceBaseTest.class); @@ -49,6 +51,7 @@ public abstract class WorkflowServiceBaseTest extends BaseTest { @Autowired protected ServiceRegistry serviceRegistry; @Autowired + @Qualifier("eu.xenit.apix.workflow.IWorkflowService") protected IWorkflowService apixWorkflowService; protected RetryingTransactionHelper transactionHelper; protected MutableAuthenticationService authenticationService; diff --git a/apix-interface/build.gradle b/apix-interface/build.gradle index c4db226d..75843c97 100644 --- a/apix-interface/build.gradle +++ b/apix-interface/build.gradle @@ -25,10 +25,11 @@ publishing { } dependencies { - compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jackson_version - compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: jackson_version - compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jackson_version - compile group: 'io.swagger', name: 'swagger-annotations', version: swagger_version - testCompile group: 'junit', name: 'junit', version: '4.12' + implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jackson_version + implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: jackson_version + implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jackson_version + implementation group: 'io.swagger', name: 'swagger-annotations', version: swagger_version +// implementation "io.swagger.core.v3:swagger-annotations:$swagger_version" + testImplementation group: 'junit', name: 'junit', version: '4.12' } diff --git a/apix-interface/src/main/java/eu/xenit/apix/configuration/Configurations.java b/apix-interface/src/main/java/eu/xenit/apix/configuration/Configurations.java index 866bd168..795b9021 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/configuration/Configurations.java +++ b/apix-interface/src/main/java/eu/xenit/apix/configuration/Configurations.java @@ -1,8 +1,6 @@ package eu.xenit.apix.configuration; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.List; public class Configurations { @@ -10,8 +8,8 @@ public class Configurations { private List files; public Configurations(List files) { - this.files = new ArrayList(files); - Collections.sort(this.files,new ConfigurationFileComparator()); + this.files = new ArrayList<>(files); + this.files.sort(new ConfigurationFileComparator()); } public List getFiles() { diff --git a/apix-interface/src/main/java/eu/xenit/apix/data/QName.java b/apix-interface/src/main/java/eu/xenit/apix/data/QName.java index 8aa8679c..cf8c5c69 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/data/QName.java +++ b/apix-interface/src/main/java/eu/xenit/apix/data/QName.java @@ -4,10 +4,12 @@ import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.JsonValue; +import java.io.Serializable; + /** * Represents an unique name in alfresco for properties and types. */ -public class QName { +public class QName implements Serializable { private String value; diff --git a/apix-interface/src/main/java/eu/xenit/apix/node/INodeService.java b/apix-interface/src/main/java/eu/xenit/apix/node/INodeService.java index 2cd5d472..44af1e61 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/node/INodeService.java +++ b/apix-interface/src/main/java/eu/xenit/apix/node/INodeService.java @@ -8,13 +8,13 @@ import eu.xenit.apix.data.StoreRef; import io.swagger.annotations.Api; import java.io.InputStream; -import java.util.Dictionary; import java.util.List; import java.util.Map; /** * Service for operations on nodes. */ +// FIXME What is this annotation doing here? @Api(value = "/metadata", produces = "application/json") public interface INodeService { diff --git a/apix-interface/src/main/java/eu/xenit/apix/search/SearchQuery.java b/apix-interface/src/main/java/eu/xenit/apix/search/SearchQuery.java index 96b5cdd7..59df93ca 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/search/SearchQuery.java +++ b/apix-interface/src/main/java/eu/xenit/apix/search/SearchQuery.java @@ -6,6 +6,7 @@ import eu.xenit.apix.data.StoreRef; import eu.xenit.apix.search.nodes.SearchSyntaxNode; import io.swagger.annotations.ApiModelProperty; +//import io.swagger.v3.oas.annotations.media.Schema; import java.util.ArrayList; import java.util.Arrays; @@ -24,6 +25,7 @@ */ public class SearchQuery { +// @Schema(required = true) @ApiModelProperty(required = true) private SearchSyntaxNode query; private PagingOptions paging = new PagingOptions(); @@ -127,8 +129,12 @@ public void setSkip(int skip) { public static class FacetOptions { private boolean enabled; + +// @Schema(description = "Limits the number of values returned per facet") @ApiModelProperty("Limits the number of values returned per facet") private Integer limit = -1; + +// @Schema(description = "Return only facet values with count >= mincount") @ApiModelProperty("Return only facet values with count >= mincount") private Integer mincount; public List custom; diff --git a/apix-interface/src/main/java/eu/xenit/apix/search/json/TypeResolver.java b/apix-interface/src/main/java/eu/xenit/apix/search/json/TypeResolver.java index 171d836a..cf4162fa 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/search/json/TypeResolver.java +++ b/apix-interface/src/main/java/eu/xenit/apix/search/json/TypeResolver.java @@ -28,12 +28,8 @@ public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType b @Override public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection subtypes) { - //if (!baseType.getRawClass().equals(SearchSyntaxNode.class)) throw new UnsupportedOperationException(); TypeNameIdResolver idRes = TypeNameIdResolver.construct(config, baseType, subtypes, false, true); - - SearchNodeTypeDeserializer s = new SearchNodeTypeDeserializer(baseType, idRes, null, false, null); - - return s; + return new SearchNodeTypeDeserializer(baseType, idRes, null, false, null); } @Override diff --git a/apix-interface/src/main/java/eu/xenit/apix/translation/PropertyTranslationValue.java b/apix-interface/src/main/java/eu/xenit/apix/translation/PropertyTranslationValue.java index 8d40d2df..433a8b1f 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/translation/PropertyTranslationValue.java +++ b/apix-interface/src/main/java/eu/xenit/apix/translation/PropertyTranslationValue.java @@ -2,6 +2,7 @@ import eu.xenit.apix.data.QName; import io.swagger.annotations.ApiModelProperty; +//import io.swagger.v3.oas.annotations.media.Schema; import java.util.Map; @@ -11,6 +12,7 @@ */ public class PropertyTranslationValue extends TranslationValue { +// @Schema(type = "Map[string,string]") @ApiModelProperty(dataType = "Map[string,string]") private Map values; diff --git a/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Optional.java b/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Optional.java index 29e1491e..c008efef 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Optional.java +++ b/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Optional.java @@ -1,26 +1,6 @@ /* * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * */ package eu.xenit.apix.utils.java8; diff --git a/apix-rest-v1/build.gradle b/apix-rest-v1/build.gradle index 7adbeb2a..2cd368e7 100644 --- a/apix-rest-v1/build.gradle +++ b/apix-rest-v1/build.gradle @@ -1,32 +1,68 @@ +plugins { + id 'java-library' + id 'idea' + id 'eu.xenit.amp' version '1.1.0' + id 'eu.xenit.alfresco' version '1.1.0' +} + description = 'Xenit API-X Rest v1' +configurations { + ampArtifact +} + +artifacts { + ampArtifact amp +} + dependencies { + implementation platform("org.alfresco:acs-community-packaging:$alfrescoVersion") +// implementation "org.springframework.boot:spring-boot-starter-parent:2.6.6" +// implementation "org.springframework.boot:spring-boot-starter-actuator:2.6.6" +//// implementation "org.springframework.boot:spring-boot-starter-integration:2.6.6" +// implementation("io.springfox:springfox-boot-starter:3.0.0") { +// exclude group: 'io.swagger', module: 'swagger-annotations' +// } +// implementation("io.springfox:springfox-swagger2:3.0.0") { +// exclude group: 'io.swagger', module: 'swagger-annotations' +// } +// implementation "io.springfox:springfox-swagger-ui:3.0.0" +// implementation "io.springfox:springfox-spring-web:3.0.0" +// implementation "io.springfox:springfox-spring-webmvc:3.0.0" +//// implementation "io.springfox:springfox-spring-integration-webmvc:3.0.0" + // Alfresco dependency should be removed in the future - compileOnly(group: 'org.alfresco', name: 'alfresco-repository', version: '5.0.d') { exclude group: 'maven-plugins' } + compileOnly("org.alfresco:alfresco-repository") compileOnly project(':apix-interface') + compileOnly('org.alfresco:alfresco-remote-api') // The REST API use one call from DE annotations-runtime for the bulk endpoint // although annotations-runtime is internal - compileOnly(group: 'eu.xenit.de', name: 'annotations-runtime', version: de_version) { transitive = false } - compileOnly(group: 'eu.xenit.de', name: 'annotations', version: de_version) { transitive = false } - compileOnly(group: 'eu.xenit.de', name: 'webscripts', version: de_version) { transitive = false } +// compileOnly(group: 'eu.xenit.de', name: 'annotations-runtime', version: de_version) { transitive = false } +// compileOnly(group: 'eu.xenit.de', name: 'annotations', version: de_version) { transitive = false } +// compileOnly(group: 'eu.xenit.de', name: 'webscripts', version: de_version) { transitive = false } + + compileOnly "com.gradecak.alfresco-mvc:alfresco-mvc-rest:$mvc" + compileOnly "javax.servlet:javax.servlet-api:4.0.1" - compile(project(':de-swagger-reader')) +// compile(project(':de-swagger-reader')) // Overriding the dependencies in swagger to use the same version everywhere, ideally we // can switch to a recent swagger version and have updated jackson versions. - compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: jackson_version - compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-joda', version: jackson_version - - testCompile group: 'org.springframework', name: 'spring-core', version: '3.2.10.RELEASE' - testCompile group: 'org.springframework', name: 'spring-test', version: '3.2.10.RELEASE' - testCompile group: 'org.springframework.extensions.surf', name: 'spring-webscripts', version: '5.0.d' - testCompile group: 'org.mockito', name: 'mockito-core', version: '2.25.1' - testCompile group: 'eu.xenit.de', name: 'annotations', version: de_version - testCompile group: 'eu.xenit.de', name: 'annotations-runtime', version: de_version - testCompile group: 'eu.xenit.de', name: 'webscripts', version: de_version - testCompile (group: 'org.alfresco', name: 'alfresco-repository', version: '5.0.d') { exclude group: 'maven-plugins' } - testCompile (group: 'org.alfresco', name: 'alfresco-remote-api', version: '5.0.d') { exclude group: 'maven-plugins' } - testCompile project(':apix-interface') - testCompile project(':apix-impl') -} +// implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml" +// implementation "com.fasterxml.jackson.datatype:jackson-datatype-joda" + implementation group: 'io.swagger', name: 'swagger-annotations', version: swagger_version + + testImplementation 'org.springframework:spring-core:3.2.10.RELEASE' + testImplementation 'org.springframework:spring-test:3.2.10.RELEASE' +// testImplementation group: 'org.springframework.extensions.surf', name: 'spring-webscripts', version: alfrescoVersion + testImplementation "org.alfresco.surf:spring-webscripts" + testImplementation group: 'org.mockito', name: 'mockito-core', version: '2.25.1' +// testImplementation group: 'eu.xenit.de', name: 'annotations', version: de_version +// testImplementation group: 'eu.xenit.de', name: 'annotations-runtime', version: de_version +// testImplementation group: 'eu.xenit.de', name: 'webscripts', version: de_version + testImplementation (group: 'org.alfresco', name: 'alfresco-repository', version: '7.2.0') + testImplementation (group: 'org.alfresco', name: 'alfresco-remote-api', version: '7.2.0') + testImplementation project(':apix-interface') + testImplementation project(':apix-impl') +} \ No newline at end of file diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java new file mode 100644 index 00000000..c30bc5f5 --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java @@ -0,0 +1,175 @@ +package eu.xenit.apix.rest; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.gradecak.alfresco.mvc.rest.config.DefaultAlfrescoMvcServletContextConfiguration; +import eu.xenit.apix.rest.jackson.Jackson2ApixNodeRefDeserializer; +import eu.xenit.apix.rest.jackson.Jackson2ApixNodeRefSerializer; +import eu.xenit.apix.rest.jackson.Jackson2ApixQnameDeserializer; +import eu.xenit.apix.rest.jackson.Jackson2ApixQnameSerializer; +import eu.xenit.apix.search.json.SearchNodeJsonParser; +import org.alfresco.rest.framework.jacksonextensions.RestJsonModule; +import org.alfresco.service.namespace.NamespaceService; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration; +import org.springframework.context.annotation.*; +import org.springframework.web.multipart.MultipartResolver; +import org.springframework.web.multipart.commons.CommonsMultipartResolver; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping; +import springfox.documentation.RequestHandler; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spi.service.RequestHandlerProvider; +import springfox.documentation.spring.web.WebMvcRequestHandler; +import springfox.documentation.spring.web.paths.Paths; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper; +import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider; +import springfox.documentation.spring.web.readers.operation.HandlerMethodResolver; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@Configuration +@EnableWebMvc +@EnableSwagger2 +@EnableAutoConfiguration(exclude = { + DataSourceAutoConfiguration.class, + ActiveMQAutoConfiguration.class, + FreeMarkerAutoConfiguration.class +}) +@PropertySource(value = { "classpath:application.properties" }) +// should pick up other controllers from the same package by default +@ComponentScan(basePackages = { "eu.xenit.apix" }) +public class AlfredApiRestServletContext extends DefaultAlfrescoMvcServletContextConfiguration { + + + public AlfredApiRestServletContext(RestJsonModule alfrescoRestJsonModule, NamespaceService namespaceService) { + super(alfrescoRestJsonModule, namespaceService); + } + + @Override + protected List> customJsonDeserializers() { + return Arrays.asList( + new Jackson2ApixNodeRefDeserializer(), + new Jackson2ApixQnameDeserializer() + ); + } + + @Override + protected List> customJsonSerilizers() { + return Arrays.asList( + new Jackson2ApixNodeRefSerializer(), + new Jackson2ApixQnameSerializer() + ); + } + + @Bean + @Primary + @Override + public ObjectMapper objectMapper() { + ObjectMapper om = new SearchNodeJsonParser().getObjectMapper(); + om.setSerializationInclusion(JsonInclude.Include.NON_NULL); + jackson2ObjectMapperBuilder().configure(om); + return om; + } + + @Override + protected MultipartResolver createMultipartResolver() { + CommonsMultipartResolver resolver = new CommonsMultipartResolver() { + @Override + public boolean isMultipart(HttpServletRequest request) { + String method = request.getMethod().toLowerCase(); + //By default, only POST is allowed. Since this is an 'update' we should accept PUT. + if (!Arrays.asList("put", "post").contains(method)) { + return false; + } + String contentType = request.getContentType(); + return (contentType != null &&contentType.toLowerCase().startsWith("multipart/")); + } + }; + resolver.setMaxUploadSize(-1); + resolver.setDefaultEncoding("utf-8"); + return resolver; + } + + @Bean + public Docket api() { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .paths(PathSelectors.ant("/api/**")) + .apis(RequestHandlerSelectors.basePackage("eu.xenit.apix")) + .build(); + } + +// @Override +// public void addResourceHandlers(ResourceHandlerRegistry registry) { +// registry.addResourceHandler("/api/swagger-ui.html**") +// .addResourceLocations("classpath:/META-INF/resources/swagger-ui.html"); +// registry.addResourceHandler("/api/webjars/**") +// .addResourceLocations("classpath:/META-INF/resources/webjars/"); +// } +// +// @Override +// public void addViewControllers(ViewControllerRegistry registry) { +// registry.addRedirectViewController( +// "/apix/v2/api-docs", +// "/v2/api-docs" +// ); +// registry.addRedirectViewController( +// "/apix/swagger-resources/configuration/ui", +// "/swagger-resources/configuration/ui" +// ); +// registry.addRedirectViewController( +// "/apix/swagger-resources/configuration/security", +// "/swagger-resources/configuration/security" +// ); +// registry.addRedirectViewController( +// "/apix/swagger-resources", +// "/swagger-resources" +// ); +// } + + @Bean + public InitializingBean removeSpringfoxHandlerProvider(DocumentationPluginsBootstrapper bootstrapper) { + return () -> bootstrapper.getHandlerProviders().removeIf(WebMvcRequestHandlerProvider.class::isInstance); + } + + @Bean + public RequestHandlerProvider customRequestHandlerProvider(Optional servletContext, + HandlerMethodResolver methodResolver, + List handlerMappings) { + String contextPath = servletContext.map(ServletContext::getContextPath).orElse(Paths.ROOT); + return () -> handlerMappings.stream() + .filter(mapping -> !mapping.getClass().getSimpleName() + .equals("IntegrationRequestMappingHandlerMapping")) + .map(mapping -> mapping.getHandlerMethods().entrySet()) + .flatMap(Set::stream) + .map(entry -> new WebMvcRequestHandler(contextPath, methodResolver, + tweakInfo(entry.getKey()), entry.getValue())) + .sorted(RequestHandler.byPatternsCondition()) + .collect(Collectors.toList()); + } + + RequestMappingInfo tweakInfo(RequestMappingInfo info) { + if (info.getPathPatternsCondition() == null) return info; + String[] patterns = info.getPathPatternsCondition().getPatternValues().toArray(String[]::new); + return info.mutate().options(new RequestMappingInfo.BuilderConfiguration()).paths(patterns).build(); + } +} \ No newline at end of file diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/SpringConfig.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/SpringConfig.java new file mode 100644 index 00000000..b2a68b9e --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/SpringConfig.java @@ -0,0 +1,12 @@ +package eu.xenit.apix.rest; + +import com.gradecak.alfresco.mvc.rest.annotation.AlfrescoDispatcherWebscript; +import com.gradecak.alfresco.mvc.rest.annotation.EnableAlfrescoMvcRest; + +@EnableAlfrescoMvcRest( + @AlfrescoDispatcherWebscript( + name = "alfred-rest.api", + servletContext = AlfredApiRestServletContext.class + ) +) +public class SpringConfig {} \ No newline at end of file diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixAbstractSerializer.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixAbstractSerializer.java new file mode 100644 index 00000000..02d320b8 --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixAbstractSerializer.java @@ -0,0 +1,29 @@ +package eu.xenit.apix.rest.jackson; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +import java.io.IOException; +import java.io.Serializable; + +public abstract class Jackson2ApixAbstractSerializer extends StdSerializer { + + private static final long serialVersionUID = 1L; + private final Class supportedClass; + + protected Jackson2ApixAbstractSerializer(Class clazz) { + super(clazz); + this.supportedClass = clazz; + } + + @Override + public void serialize(T value, JsonGenerator jgen, SerializerProvider provider) throws IOException { + jgen.writeString(value.toString()); + } + + @Override + public Class handledType() { + return supportedClass; + } +} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixNodeRefDeserializer.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixNodeRefDeserializer.java new file mode 100644 index 00000000..ff08204d --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixNodeRefDeserializer.java @@ -0,0 +1,29 @@ +package eu.xenit.apix.rest.jackson; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import eu.xenit.apix.data.NodeRef; +import org.springframework.core.convert.converter.Converter; + +import java.io.IOException; + +public class Jackson2ApixNodeRefDeserializer extends JsonDeserializer implements Converter { + + @Override + public Class handledType() { + return NodeRef.class; + } + + @Override + public NodeRef deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + return new NodeRef( + jp.getText() + ); + } + + @Override + public NodeRef convert(String nodeRef) { + return new NodeRef(nodeRef); + } +} \ No newline at end of file diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixNodeRefSerializer.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixNodeRefSerializer.java new file mode 100644 index 00000000..176586e5 --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixNodeRefSerializer.java @@ -0,0 +1,12 @@ +package eu.xenit.apix.rest.jackson; + +import eu.xenit.apix.data.NodeRef; + +public class Jackson2ApixNodeRefSerializer extends Jackson2ApixAbstractSerializer { + + private static final long serialVersionUID = 1L; + + public Jackson2ApixNodeRefSerializer() { + super(NodeRef.class); + } +} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixQnameDeserializer.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixQnameDeserializer.java new file mode 100644 index 00000000..d1d5ff4e --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixQnameDeserializer.java @@ -0,0 +1,29 @@ +package eu.xenit.apix.rest.jackson; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import eu.xenit.apix.data.QName; +import org.springframework.core.convert.converter.Converter; + +import java.io.IOException; + +public class Jackson2ApixQnameDeserializer extends JsonDeserializer implements Converter { + + @Override + public Class handledType() { + return QName.class; + } + + @Override + public QName deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + return new QName( + jp.getText() + ); + } + + @Override + public QName convert(String qname) { + return new QName(qname); + } +} \ No newline at end of file diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixQnameSerializer.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixQnameSerializer.java new file mode 100644 index 00000000..8d9504df --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/jackson/Jackson2ApixQnameSerializer.java @@ -0,0 +1,12 @@ +package eu.xenit.apix.rest.jackson; + +import eu.xenit.apix.data.QName; + +public class Jackson2ApixQnameSerializer extends Jackson2ApixAbstractSerializer { + + private static final long serialVersionUID = 1L; + + public Jackson2ApixQnameSerializer() { + super(QName.class); + } +} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/ApixStagingWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/ApixStagingWebscript.java deleted file mode 100644 index 5e370003..00000000 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/ApixStagingWebscript.java +++ /dev/null @@ -1,34 +0,0 @@ -package eu.xenit.apix.rest.staging; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import eu.xenit.apix.data.NodeRef; -import eu.xenit.apix.filefolder.IFileFolderService; -import eu.xenit.apix.node.*; -import eu.xenit.apix.permissions.IPermissionService; -import eu.xenit.apix.permissions.PermissionValue; -import eu.xenit.apix.rest.v1.nodes.NodeInfo; -import org.alfresco.repo.admin.SysAdminParams; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptResponse; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class ApixStagingWebscript { - - private final static Logger logger = LoggerFactory.getLogger(ApixStagingWebscript.class); - - protected void writeJsonResponse(WebScriptResponse response, Object object) throws IOException { - response.setContentType("application/json"); - response.setContentEncoding("utf-8"); - response.setHeader("Cache-Control", "no-cache"); - ObjectMapper mapper = new ObjectMapper(); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.writeValue(response.getWriter(), object); - } -} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/RestStagingConfig.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/RestStagingConfig.java deleted file mode 100644 index 715d50dd..00000000 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/RestStagingConfig.java +++ /dev/null @@ -1,8 +0,0 @@ -package eu.xenit.apix.rest.staging; - -public class RestStagingConfig { - - public static final String BaseUrl = "/apix/staging"; - public static final String ApixUrl = "/apix"; - public static final String Family = "Api-X Staging API (Unstable)"; -} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowJsonParser.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowJsonParser.java deleted file mode 100644 index 13eb80e2..00000000 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowJsonParser.java +++ /dev/null @@ -1,10 +0,0 @@ -package eu.xenit.apix.rest.staging.workflow; - -import com.fasterxml.jackson.databind.ObjectMapper; - -public class WorkflowJsonParser { - - public ObjectMapper getObjectMapper() { - return new ObjectMapper(); - } -} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java index 868b79d1..acfbd067 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java @@ -1,18 +1,6 @@ package eu.xenit.apix.rest.staging.workflow; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.util.ISO8601DateFormat; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; -import eu.xenit.apix.rest.staging.ApixStagingWebscript; -import eu.xenit.apix.rest.staging.RestStagingConfig; -import eu.xenit.apix.rest.v1.ExceptionObject; import eu.xenit.apix.search.SearchQueryResult; import eu.xenit.apix.workflow.IWorkflowService; import eu.xenit.apix.workflow.model.Task; @@ -29,32 +17,29 @@ import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; -import java.io.InputStream; import java.io.Serializable; import java.util.Arrays; import java.util.HashSet; import java.util.List; -import java.util.ListIterator; import java.util.Map; import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; -@WebScript(baseUri = RestStagingConfig.BaseUrl, families = RestStagingConfig.Family, defaultFormat = "json", - description = "Perform workflow and task operations", value = "Workflows") -@Authentication(AuthenticationType.USER) -@Qualifier("eu.xenit.apix.rest.staging.workflow.WorkflowWebscript") -@Component("eu.xenit.apix.rest.staging.workflow.WorkflowWebscript") -public class WorkflowWebscript extends ApixStagingWebscript { - - public static final ISO8601DateFormat DATE_FORMAT = new ISO8601DateFormat(); +@RestController +public class WorkflowWebscript { + private static final Logger logger = LoggerFactory.getLogger(WorkflowWebscript.class); /// private static final String WorkflowSearchQueryDocumentationSample = "{\n" + @@ -96,42 +81,38 @@ public class WorkflowWebscript extends ApixStagingWebscript { "}"; /// - @Qualifier("eu.xenit.apix.workflow.IWorkflowService") - @Autowired - IWorkflowService workflowService; + private final IWorkflowService workflowService; - Logger logger = LoggerFactory.getLogger(WorkflowWebscript.class); + public WorkflowWebscript(@Qualifier("eu.xenit.apix.workflow.IWorkflowService") IWorkflowService workflowService) { + this.workflowService = workflowService; + } - @Uri(value = "/workflows/definitions", method = HttpMethod.GET, defaultFormat = "json") + @GetMapping( + value = "/staging/workflows/definitions", + produces = MediaType.APPLICATION_JSON_VALUE + ) @ApiOperation(value = "Retrieve the definitions for all defined workflows") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = WorkflowDefinitionList.class)) - public void getWorkflowDefinitions(@RequestParam(delimiter = ",", required = false) - @ApiParam(value = "Comma separated definition names to exclude.") String[] exclude, - WebScriptResponse response) throws IOException { + public ResponseEntity getWorkflowDefinitions(@RequestParam(required = false) + @ApiParam(value = "Comma separated definition names to exclude.") String[] exclude) { List definitions = workflowService.getAllDefinitions(); if (exclude != null && exclude.length > 0) { HashSet excludeSet = new HashSet<>(Arrays.asList(exclude)); - ListIterator iter = definitions.listIterator(); - while (iter.hasNext()) { - if (excludeSet.contains(iter.next().name)) { - iter.remove(); - } - } + definitions.removeIf(workflowDefinition -> excludeSet.contains(workflowDefinition.name)); } - writeJsonResponse(response, new WorkflowDefinitionList(definitions)); + return responseFrom(new WorkflowDefinitionList(definitions)); } - @Uri(value = "/workflows/definition/{name}", method = HttpMethod.GET) + @GetMapping(value = "/workflows/definition/{name}") @ApiOperation(value = "Retrieve the definition for the specified workflow name") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = WorkflowDefinition.class)) - public void getWorkflowDefinition(@UriVariable final String name, WebScriptResponse response) throws IOException { - WorkflowDefinition definition = workflowService.getWorkflowDefinition(name); - writeJsonResponse(response, definition); + public ResponseEntity getWorkflowDefinition(@PathVariable final String name) { + return responseFrom(workflowService.getWorkflowDefinition(name)); } - @Uri(value = "/workflows/search", method = HttpMethod.POST) + @PostMapping(value = "/workflows/search") @ApiOperation(value = "Returns a collection of workflow instances", notes = "The result collection of workflow instances is sorted and filtered as requested in the provided" + " WorkflowSearchQuery\nWorkflowSearchQuery Sample:\n" + WorkflowSearchQueryDocumentationSample) @@ -140,20 +121,14 @@ public void getWorkflowDefinition(@UriVariable final String name, WebScriptRespo dataType = "eu.xenit.apix.workflow.WorkflowSearchQuery", paramType = "body", name = "body")}) - public void workflowsActiviti(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) - throws IOException { - ObjectMapper m = new WorkflowJsonParser().getObjectMapper(); - m.setDateFormat(DATE_FORMAT); - InputStream stream = webScriptRequest.getContent().getInputStream(); - WorkflowSearchQuery q = m.readValue(stream, WorkflowSearchQuery.class); - TaskOrWorkflowSearchResult result = workflowService.searchWorkflows(q); - logger.debug("Found results for workflows"); - logger.debug("Nb of results: " + result.results.size()); + public ResponseEntity workflowsActiviti(@RequestBody final WorkflowSearchQuery query) { + TaskOrWorkflowSearchResult result = workflowService.searchWorkflows(query); + logger.debug("Found results for workflows, # of results: {}", result.results.size()); result.getFacets().CheckValidity(); - writeJsonResponse(webScriptResponse, result); + return responseFrom(result); } - @Uri(value = "/tasks/search", method = HttpMethod.POST) + @PostMapping(value = "/tasks/search") @ApiOperation(value = "Returns a collection of workflow tasks", notes = "The result collection of workflow tasks is sorted and filtered as requested in the provided" + " TaskSearchQuery\nTaskSearchQuery Sample:\n" + TaskSearchQueryDocumentationSample) @@ -162,41 +137,33 @@ public void workflowsActiviti(WebScriptRequest webScriptRequest, WebScriptRespon dataType = "eu.xenit.apix.workflow.TaskSearchQuery", paramType = "body", name = "body")}) - public void tasksActiviti(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) - throws IOException { - ObjectMapper m = new WorkflowJsonParser().getObjectMapper(); - InputStream stream = webScriptRequest.getContent().getInputStream(); - TaskSearchQuery q = m.readValue(stream, TaskSearchQuery.class); - TaskOrWorkflowSearchResult result = workflowService.searchTasks(q); - writeJsonResponse(webScriptResponse, result); + public ResponseEntity tasksActiviti(@RequestBody final TaskSearchQuery query) { + return responseFrom(workflowService.searchTasks(query)); } - @Uri(value = "/workflows/{id}", method = HttpMethod.GET) + @GetMapping(value = "/workflows/{id}") @ApiOperation(value = "Retrieves a workflow with the provided id") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Task.class)) - public void workflow(@UriVariable final String id, WebScriptResponse response) throws IOException { - writeJsonResponse(response, workflowService.getWorkflowInfo(id)); + public ResponseEntity workflow(@PathVariable final String id) { + return responseFrom(workflowService.getWorkflowInfo(id)); } - @Uri(value = "/workflows/{id}/start", method = HttpMethod.POST) - public void startWorkflow(@UriVariable final String id, @RequestBody Map variables, - WebScriptResponse response) throws IOException { - for (Map.Entry e : variables.entrySet()) { - logger.debug("{}: {}", e.getKey(), e.getValue()); - } - - Workflow workflow = workflowService.startWorkflow(id, variables); - writeJsonResponse(response, workflow); + @PostMapping(value = "/workflows/{id}/start") + public ResponseEntity startWorkflow(@PathVariable final String id, + @RequestBody final Map variables) { + logger.debug("variables: {}", variables); + return responseFrom(workflowService.startWorkflow(id, variables)); } - @Uri(value = "/tasks/{id}", method = HttpMethod.GET) + @GetMapping(value = "/tasks/{id}") @ApiOperation(value = "Retrieves a workflow task with the provided id") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Task.class)) - public void task(@UriVariable final String id, WebScriptResponse response) throws IOException { - writeJsonResponse(response, workflowService.getTaskInfo(id)); + public ResponseEntity task(@PathVariable final String id) { + responseFrom(workflowService.getTaskInfo(id)); + return ResponseEntity.ok().build(); } - @Uri(value = "/workflows/{id}", method = HttpMethod.PUT) + @PutMapping(value = "/workflows/{id}") @ApiOperation(value = "[Deprecated] Updates a workflow with the provided id, with the provided information from" + " the provided WorkflowChanges\nWorkflowChanges Sample:\n" + WorkflowChangesOrTaskChangesDocumentationSample) @@ -205,26 +172,20 @@ public void task(@UriVariable final String id, WebScriptResponse response) throw dataType = "eu.xenit.apix.workflow.model.WorkflowChanges", paramType = "body", name = "body")}) - public void updateWorkflow( - @UriVariable String id, - WorkflowOrTaskChanges changes, - WebScriptRequest webScriptRequest, - WebScriptResponse webScriptResponse) throws IOException { - Workflow ret = workflowService.updateWorkflow(id, changes); - writeJsonResponse(webScriptResponse, ret); + public ResponseEntity updateWorkflow(@PathVariable final String id, + @RequestBody final WorkflowOrTaskChanges changes) { + return responseFrom(workflowService.updateWorkflow(id, changes)); } - @Uri(value = "/workflows/{id}", method = HttpMethod.DELETE) + @DeleteMapping(value = "/workflows/{id}") @ApiOperation(value = "Cancels a workflow with the provided id") @ApiResponses(@ApiResponse(code = 200, message = "Success")) - public void cancelWorkflow( - @UriVariable String id, - WebScriptRequest webScriptRequest, - WebScriptResponse webScriptResponse) throws IOException { + public ResponseEntity cancelWorkflow(@PathVariable final String id) { workflowService.cancelWorkflow(id); + return ResponseEntity.ok().build(); } - @Uri(value = "/tasks/{id}", method = HttpMethod.PUT) + @PutMapping(value = "/tasks/{id}") @ApiOperation(value = "Updates a workflow task with the provided id, with the provided information from" + " the provided TaskChanges\nTaskChanges Sample:\n" + WorkflowChangesOrTaskChangesDocumentationSample) @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Task.class)) @@ -232,22 +193,18 @@ public void cancelWorkflow( dataType = "eu.xenit.apix.workflow.model.TaskChanges", paramType = "body", name = "body")}) - public void updateTask( - @UriVariable String id, - WorkflowOrTaskChanges changes, - WebScriptRequest webScriptRequest, - WebScriptResponse webScriptResponse - ) throws IOException { + public ResponseEntity updateTask(@PathVariable final String id, + @RequestBody final WorkflowOrTaskChanges changes) { try { - Task ret = workflowService.updateTask(id, changes); - writeJsonResponse(webScriptResponse, ret); + return responseFrom(workflowService.updateTask(id, changes)); } catch (Error ex) { - webScriptResponse.setStatus(HttpStatus.SC_CONFLICT); - writeJsonResponse(webScriptResponse, new ExceptionObject(ex)); + return ResponseEntity.status(HttpStatus.SC_CONFLICT).build(); + // TODO @Zlatin Alfresco MVC +// responseFrom(webScriptResponse, ex); } } - @Uri(value = "/tasks/claim", method = HttpMethod.POST) + @PostMapping(value = "/staging/tasks/claim") @ApiOperation(value = "Claims the task with the provided id for a user", notes = "The user parameter is optional. If not provided, Alfred API will default to the current user") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = SearchQueryResult.class)) @@ -255,65 +212,51 @@ public void updateTask( dataType = "String", paramType = "body", name = "body")}) - public void claimTask(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) throws IOException { - ObjectMapper m = new WorkflowJsonParser().getObjectMapper(); - JsonNode input = m.readTree(webScriptRequest.getContent().getContent()); - logger.debug("Input: " + input); - JsonNode id = input.get("id"); - JsonNode userName = input.get("userName"); + public ResponseEntity claimTask(@RequestBody final Map body) { + logger.debug("Input: {}", body); + String id = body.get("id"); + String userName = body.get("userName"); Task wfTask; if (userName != null) { - logger.debug("Setting owner of task with id " + id.asText() + " to " + userName); - wfTask = workflowService.claimWorkflowTask(id.asText(), userName.asText()); + logger.debug("Setting owner of task with id {} to {}", id, userName); + wfTask = workflowService.claimWorkflowTask(id, userName); } else { logger.debug("Setting owner of task with id "); - wfTask = workflowService.claimWorkflowTask(id.asText()); + wfTask = workflowService.claimWorkflowTask(id); } - writeJsonResponse(webScriptResponse, wfTask); + return responseFrom(wfTask); } - @Uri(value = "/tasks/release", method = HttpMethod.POST) + @PostMapping(value = "/staging/tasks/release") @ApiOperation(value = "Releases the task with the provided id") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = SearchQueryResult.class)) @ApiImplicitParams({@ApiImplicitParam( dataType = "String", paramType = "body", name = "body")}) - public void releaseTask(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) - throws IOException { - ObjectMapper m = new WorkflowJsonParser().getObjectMapper(); - JsonNode input = m.readTree(webScriptRequest.getContent().getContent()); - logger.debug("Input: " + input); - JsonNode id = input.get("id"); - - logger.debug("Setting owner of task with id " + id.asText()); - Task wfTask = workflowService.releaseWorkflowTask(id.asText()); - writeJsonResponse(webScriptResponse, wfTask); + public ResponseEntity releaseTask(@RequestBody final Map body) { + logger.debug("Setting owner of task {}", body); + String id = body.get("id"); + Task wfTask = workflowService.releaseWorkflowTask(id); + return responseFrom(wfTask); } - @Uri(value = "/tasks/{id}/end/{transition}", method = HttpMethod.POST) + @PostMapping(value = "/staging/tasks/{id}/end/{transition}") @ApiOperation(value = "Ends the workflow task with the provided id with the provided transition as next") @ApiResponses(@ApiResponse(code = 200, message = "Success")) - public void transitionTask(@UriVariable String id, @UriVariable String transition) { + public void transitionTask(@PathVariable String id, @PathVariable String transition) { workflowService.endTask(id, transition); } - @Uri(value = "/workflows/generate/{amount}/{username}", method = HttpMethod.GET) + @GetMapping(value = "/staging/workflows/generate/{amount}/{username}") @ApiOperation(value = "[DEV] Generate an amount of workflows for username") @ApiResponses(@ApiResponse(code = 200, message = "Success")) - public void generateWorkflow(@UriVariable final int amount, @UriVariable final String username) { + public void generateWorkflow(@PathVariable final int amount, @PathVariable final String username) { workflowService.GenerateWorkflows(amount, username); } - //Include correct date format - protected void writeJsonResponse(WebScriptResponse response, Object object) throws IOException { - response.setContentType("application/json"); - response.setContentEncoding("utf-8"); - response.setHeader("Cache-Control", "no-cache"); - ObjectMapper mapper = new ObjectMapper(); - mapper.setDateFormat(new ISO8601DateFormat()); - //mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.writeValue(response.getWriter(), object); + protected ResponseEntity responseFrom(T object) { + return ResponseEntity.ok(object); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/RestV0Config.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/RestV0Config.java deleted file mode 100644 index 85d9ce6f..00000000 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/RestV0Config.java +++ /dev/null @@ -1,10 +0,0 @@ -package eu.xenit.apix.rest.v0; - -/** - * Created by Michiel Huygen on 09/03/2016. - */ -public class RestV0Config { - - //public static final String BaseUrl = "/apix/v1"; - public static final String Family = "Api-X v0"; -} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/categories/ClassificationGetWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/categories/ClassificationGetWebscript.java index 43c77b7c..e0259601 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/categories/ClassificationGetWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/categories/ClassificationGetWebscript.java @@ -1,42 +1,32 @@ package eu.xenit.apix.rest.v0.categories; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; +import eu.xenit.apix.categories.Category; import eu.xenit.apix.categories.ICategoryService; import eu.xenit.apix.data.QName; -import eu.xenit.apix.rest.v0.RestV0Config; -import java.io.IOException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.AbstractWebScript; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import java.util.List; -/** - * Created by Michiel Huygen on 01/12/2015. - */ -@WebScript(families = {RestV0Config.Family}, defaultFormat = "json") -@Component("eu.xenit.apix.rest.v0.categories.ClassificationGetWebscript") -@Authentication(AuthenticationType.USER) -public class ClassificationGetWebscript extends AbstractWebScript { +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; - @Autowired - private ICategoryService catService; +@RestController +public class ClassificationGetWebscript { - @Uri("/eu/xenit/classification/{aspectqname}") - @Override() - public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException { - - QName aspectQname = new QName(req.getServiceMatch().getTemplateVars().get("aspectqname")); - - ObjectMapper m = new ObjectMapper(); - String ret = m.writeValueAsString(catService.getCategoryTree(aspectQname)); - - res.getWriter().write(ret); + private final ICategoryService catService; + public ClassificationGetWebscript(ICategoryService catService) { + this.catService = catService; + } + @GetMapping( + value = "/v0/classification/{aspectQName}", + produces = MediaType.APPLICATION_JSON_VALUE + ) + public ResponseEntity> execute(@PathVariable final QName aspectQName) { + return ResponseEntity.ok( + catService.getCategoryTree(aspectQName) + ); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/dictionary/DictionaryServiceChecksumWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/dictionary/DictionaryServiceChecksumWebscript.java index ac5342b2..060f4fc2 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/dictionary/DictionaryServiceChecksumWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/dictionary/DictionaryServiceChecksumWebscript.java @@ -1,47 +1,33 @@ package eu.xenit.apix.rest.v0.dictionary; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.dictionary.IDictionaryService; -import eu.xenit.apix.rest.v0.RestV0Config; -import java.io.IOException; -import org.alfresco.service.ServiceRegistry; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.AbstractWebScript; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import java.util.Collections; +import java.util.Map; -@Component("eu.xenit.apix.rest.v0.dictionary.DictionaryServiceChecksumWebscript") -@WebScript(families = {RestV0Config.Family}, defaultFormat = "json") -@Authentication(AuthenticationType.USER) -public class DictionaryServiceChecksumWebscript extends AbstractWebScript { +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; - @Autowired - private IDictionaryService service; - @Autowired - private ServiceRegistry serviceRegistry; +@RestController +public class DictionaryServiceChecksumWebscript { - @Override - @Uri(value = "/eu/xenit/dictionary/checksum", method = HttpMethod.GET) - public void execute(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) throws IOException { + private final IDictionaryService service; - long checksum = service.getContentModelCheckSum(); - - ObjectMapper m = new ObjectMapper(); - - com.fasterxml.jackson.databind.node.ObjectNode ret = m.createObjectNode(); - ret.put("checksum", checksum); - webScriptResponse.setContentType("json"); - webScriptResponse.getWriter().write(ret.toString()); + public DictionaryServiceChecksumWebscript(IDictionaryService service) { + this.service = service; } - public void setServiceRegistry(ServiceRegistry serviceRegistry) { - this.serviceRegistry = serviceRegistry; + @GetMapping( + value = "/v0/dictionary/checksum", + produces = MediaType.APPLICATION_JSON_VALUE + ) + public ResponseEntity> execute() { + return ResponseEntity.ok( + Collections.singletonMap( + "checksum", + service.getContentModelCheckSum() + ) + ); } - } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataBulkWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataBulkWebscript.java index 34103809..db647924 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataBulkWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataBulkWebscript.java @@ -1,76 +1,37 @@ package eu.xenit.apix.rest.v0.metadata; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.node.INodeService; import eu.xenit.apix.permissions.IPermissionService; -import eu.xenit.apix.rest.v0.RestV0Config; -import java.io.IOException; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; -import org.alfresco.service.ServiceRegistry; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.AbstractWebScript; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; -@WebScript(families = {RestV0Config.Family}, defaultFormat = "json") -@Component("eu.xenit.apix.rest.v0.metadata.MetadataBulkWebscript") -@Authentication(AuthenticationType.USER) -public class MetadataBulkWebscript extends AbstractWebScript { +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; - @Autowired - private INodeService service; - @Autowired - private IPermissionService permissionService; - @Autowired - private ServiceRegistry serviceRegistry; +@RestController +public class MetadataBulkWebscript { - @Uri(value = "/eu/xenit/metadata/bulk", method = HttpMethod.POST) - @Override - public void execute(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) throws IOException { - ObjectMapper m = new ObjectMapper(); + private final INodeService service; + private final IPermissionService permissionService; - JsonNode input = m.readTree(webScriptRequest.getContent().getContent()); - if (!input.isArray()) { - throw new RuntimeException("Should be an array of noderefs"); - } - - List refs = new ArrayList<>(input.size()); - Iterator iterator = input.elements(); - while (iterator.hasNext()) { - refs.add(new NodeRef(iterator.next().asText())); - } + public MetadataBulkWebscript(INodeService service, IPermissionService permissionService) { + this.service = service; + this.permissionService = permissionService; + } + @PostMapping( + value = "/v0/eu/xenit/metadata/bulk", + produces = MediaType.APPLICATION_JSON_VALUE + ) + public ResponseEntity> execute(@RequestBody final List nodeRefs) { List metadatas = new ArrayList<>(); - - for (NodeRef el : refs) { + for (NodeRef el : nodeRefs) { metadatas.add(NodeMetadataV0.FromV1(service.getMetadata(el), permissionService)); } - - ArrayNode node = m.createArrayNode(); - - for (NodeMetadataV0 metadata : metadatas) { - node.add(m.valueToTree(metadata)); - } - - String retStr = node.toString(); - - webScriptResponse.setContentType("json"); - webScriptResponse.getWriter().write(retStr); + return ResponseEntity.ok(metadatas); } - - public void setServiceRegistry(ServiceRegistry serviceRegistry) { - this.serviceRegistry = serviceRegistry; - } - } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataGetWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataGetWebscript.java index 2ed6225d..1fa2abee 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataGetWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataGetWebscript.java @@ -1,48 +1,33 @@ package eu.xenit.apix.rest.v0.metadata; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.node.INodeService; -import eu.xenit.apix.node.NodeMetadata; import eu.xenit.apix.permissions.IPermissionService; -import eu.xenit.apix.rest.v0.RestV0Config; -import java.io.IOException; -import org.alfresco.service.ServiceRegistry; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.AbstractWebScript; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; -@WebScript(families = {RestV0Config.Family}, defaultFormat = "json") -@Component("eu.xenit.apix.rest.v0.metadata.MetadataGetWebscript") -@Authentication(AuthenticationType.USER) -public class MetadataGetWebscript extends AbstractWebScript { - @Autowired - private INodeService service; - @Autowired - private IPermissionService permissionService; - @Autowired - private ServiceRegistry serviceRegistry; +@RestController +public class MetadataGetWebscript { + private final INodeService service; + private final IPermissionService permissionService; - @Uri(value = "/eu/xenit/metadata", method = HttpMethod.GET) - @Override - public void execute(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) throws IOException { - ObjectMapper m = new ObjectMapper(); - NodeRef noderef = new NodeRef(webScriptRequest.getParameter("noderef")); - NodeMetadata metadata = service.getMetadata(noderef); - String retStr = m.writeValueAsString(NodeMetadataV0.FromV1(metadata, permissionService)); - webScriptResponse.setContentType("json"); - webScriptResponse.getWriter().write(retStr); + public MetadataGetWebscript(INodeService service, IPermissionService permissionService) { + this.service = service; + this.permissionService = permissionService; } - public void setServiceRegistry(ServiceRegistry serviceRegistry) { - this.serviceRegistry = serviceRegistry; + @GetMapping( + value = "/v0/eu/xenit/metadata", + produces = MediaType.APPLICATION_JSON_VALUE + ) + public ResponseEntity execute(@RequestParam final NodeRef nodeRef) { + return ResponseEntity.ok( + NodeMetadataV0.FromV1( + service.getMetadata(nodeRef), permissionService + ) + ); } - } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataPostWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataPostWebscript.java index 35c6cbfd..7ac68299 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataPostWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataPostWebscript.java @@ -1,51 +1,36 @@ package eu.xenit.apix.rest.v0.metadata; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.node.INodeService; -import eu.xenit.apix.node.NodeMetadata; import eu.xenit.apix.permissions.IPermissionService; -import eu.xenit.apix.rest.v0.RestV0Config; -import java.io.IOException; -import org.alfresco.service.ServiceRegistry; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.AbstractWebScript; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; -@WebScript(families = {RestV0Config.Family}, defaultFormat = "json") -@Component("eu.xenit.apix.rest.v0.metadata.MetadataPostWebscript") -@Authentication(AuthenticationType.USER) -public class MetadataPostWebscript extends AbstractWebScript { +@RestController +public class MetadataPostWebscript { - @Autowired - private INodeService service; - @Autowired - private IPermissionService permissionService; - @Autowired - private ServiceRegistry serviceRegistry; + private final INodeService service; + private final IPermissionService permissionService; - @Uri(value = "/eu/xenit/metadata", method = HttpMethod.POST) - @Override - public void execute(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) throws IOException { - ObjectMapper m = new ObjectMapper(); - NodeRef noderef = new NodeRef(webScriptRequest.getParameter("noderef")); - MetadataChangesV0 changes = m.readValue( - webScriptRequest.getContent().getInputStream(), MetadataChangesV0.class); - - NodeMetadata metadata = service.setMetadata(noderef, changes.ToV1()); - String retStr = m.writeValueAsString(NodeMetadataV0.FromV1(metadata, permissionService)); - webScriptResponse.setContentType("json"); - webScriptResponse.getWriter().write(retStr); + public MetadataPostWebscript(INodeService service, IPermissionService permissionService) { + this.service = service; + this.permissionService = permissionService; } - public void setServiceRegistry(ServiceRegistry serviceRegistry) { - this.serviceRegistry = serviceRegistry; + @PostMapping( + value = "/eu/xenit/metadata", + produces = MediaType.APPLICATION_JSON_VALUE + ) + public ResponseEntity execute(@RequestParam final NodeRef nodeRef, + @RequestBody final MetadataChangesV0 changes) { + return ResponseEntity.ok( + NodeMetadataV0.FromV1( + service.setMetadata(nodeRef, changes.ToV1()), permissionService + ) + ); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchWebScript0.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchWebScript0.java index 4d31ee70..c7db1897 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchWebScript0.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchWebScript0.java @@ -1,78 +1,35 @@ package eu.xenit.apix.rest.v0.search; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; -import eu.xenit.apix.rest.v0.RestV0Config; import eu.xenit.apix.search.ISearchService; import eu.xenit.apix.search.SearchQueryResult; -import eu.xenit.apix.search.json.SearchNodeJsonParser; -import java.io.IOException; -import org.alfresco.service.ServiceRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; -@WebScript(families = {RestV0Config.Family}, defaultFormat = "json", value = "Search") -@Component("eu.xenit.apix.rest.v0.search.SearchWebScriptV0") -@Qualifier("eu.xenit.apix.rest.v0.search.SearchWebScriptV0") -@Authentication(AuthenticationType.USER) +@RestController public class SearchWebScript0 { + private static final Logger logger = LoggerFactory.getLogger(SearchWebScript0.class); + private final ISearchService service; - Logger logger = LoggerFactory.getLogger(SearchWebScript0.class); - @Autowired - private ISearchService service; - @Autowired - private ServiceRegistry serviceRegistry; - - @Uri(value = "/eu/xenit/search", method = HttpMethod.POST) - public void execute(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) throws IOException { - - logger.debug(webScriptRequest.toString()); + public SearchWebScript0(ISearchService service) { + this.service = service; + } - ObjectMapper m = new SearchNodeJsonParser().getObjectMapper(); - SearchQueryV0 q; - try { - q = m.readValue(webScriptRequest.getContent().getInputStream(), SearchQueryV0.class); - } catch (Exception e) { - webScriptResponse.setStatus(500); - webScriptResponse.getWriter().write("Error occured during reading of search query"); - webScriptResponse.getWriter().write(e.getMessage()); - webScriptResponse.getWriter().write(e.getStackTrace().toString()); - return; - } + @PostMapping( + value = "/v0/eu/xenit/search", + produces = MediaType.APPLICATION_JSON_VALUE + ) + public ResponseEntity execute(@RequestBody final SearchQueryV0 query){ + logger.debug("query: {}", query); SearchQueryResult result; - try { - result = service.query(q.toV1()); - } catch (Exception e) { - webScriptResponse.setStatus(500); - webScriptResponse.getWriter().write("Error occured while searching"); - webScriptResponse.getWriter().write(e.getMessage()); - webScriptResponse.getWriter().write(e.getStackTrace().toString()); - return; - } - + result = service.query(query.toV1()); for (eu.xenit.apix.search.FacetSearchResult f : result.getFacets()) { f.setName("@" + f.getName()); } - - ObjectMapper mapper = new ObjectMapper(); - com.fasterxml.jackson.databind.ObjectWriter wr = mapper.writerWithType(SearchQueryResult.class); - String retStr = wr.writeValueAsString(result); - - webScriptResponse.setContentType("json"); - webScriptResponse.getWriter().write(retStr); + return ResponseEntity.ok(result); } - - public void setServiceRegistry(ServiceRegistry serviceRegistry) { - this.serviceRegistry = serviceRegistry; - } - } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java index 508c69b1..f7f86753 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java @@ -1,8 +1,5 @@ package eu.xenit.apix.rest.v1; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.util.ISO8601DateFormat; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.filefolder.IFileFolderService; import eu.xenit.apix.node.ChildParentAssociation; @@ -13,45 +10,25 @@ import eu.xenit.apix.permissions.IPermissionService; import eu.xenit.apix.permissions.PermissionValue; import eu.xenit.apix.rest.v1.nodes.NodeInfo; -import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; -import org.alfresco.repo.admin.SysAdminParams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptResponse; +import org.springframework.http.ResponseEntity; -/** - * Created by kenneth on 14.03.16. - */ public class ApixV1Webscript { - private final static Logger logger = LoggerFactory.getLogger(ApixV1Webscript.class); + private static final Logger logger = LoggerFactory.getLogger(ApixV1Webscript.class); - @Autowired - SysAdminParams sysAdminParams; - - protected void writeJsonResponse(WebScriptResponse response, Object object) throws IOException { - response.setContentType("application/json"); - response.setContentEncoding("utf-8"); - response.setHeader("Cache-Control", "no-cache"); - ObjectMapper mapper = new ObjectMapper(); - mapper.setDateFormat(new ISO8601DateFormat()); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.writeValue(response.getWriter(), object); + protected ResponseEntity writeJsonResponse(T object) { + return ResponseEntity.ok(object); } protected NodeRef createNodeRef(String space, String store, String guid) { return new NodeRef(space, store, guid); } - public String removeEscapeCharacters(String str) { - return str.replace("\\", ""); - } - protected List nodeRefToNodeInfo(List nodeRefs, IFileFolderService fileFolderService, INodeService nodeService, diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/DocumentationWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/DocumentationWebscript.java index 189e57dc..55918f74 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/DocumentationWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/DocumentationWebscript.java @@ -1,206 +1,201 @@ -package eu.xenit.apix.rest.v1; - -import com.fasterxml.jackson.databind.type.SimpleType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; -import eu.xenit.apix.data.NodeRef; -import eu.xenit.apix.data.QName; -import eu.xenit.apix.rest.v1.bulk.BulkWebscript1; -import eu.xenit.apix.rest.v1.categories.CategoryWebScript1; -import eu.xenit.apix.rest.v1.configuration.ConfigurationWebscript1; -import eu.xenit.apix.rest.v1.dictionary.DictionaryWebScript1; -import eu.xenit.apix.rest.v1.nodes.NodesWebscript1; -import eu.xenit.apix.rest.v1.people.PeopleWebscript1; -import eu.xenit.apix.rest.v1.properties.PropertiesWebScript1; -import eu.xenit.apix.rest.v1.search.SearchWebScript1; -import eu.xenit.apix.rest.v1.sites.SitesWebscript1; -import eu.xenit.apix.rest.v1.temp.WIPWebscript; -import eu.xenit.apix.rest.v1.translation.TranslationsWebscript1; -import eu.xenit.apix.rest.v1.versionhistory.VersionHistoryWebScript1; -import eu.xenit.apix.rest.v1.workingcopies.WorkingcopiesWebscript1; -import eu.xenit.apix.rest.v2.RestV2Config; -import eu.xenit.apix.rest.v2.nodes.NodesWebscriptV2; -import eu.xenit.apix.version.IVersionService; -import eu.xenit.apix.web.IWebUtils; -import eu.xenit.swagger.reader.Reader; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.converter.ModelConverter; -import io.swagger.converter.ModelConverterContext; -import io.swagger.converter.ModelConverters; -import io.swagger.models.Model; -import io.swagger.models.ModelImpl; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Response; -import io.swagger.models.Scheme; -import io.swagger.models.Swagger; -import io.swagger.models.properties.FileProperty; -import io.swagger.models.properties.Property; -import io.swagger.util.Json; -import java.io.IOException; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.surf.util.URLEncoder; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; - -@WebScript( - baseUri = RestV1Config.BaseUrl + "/docs", - families = {RestV1Config.Family}, - defaultFormat = "json", - description = "Access API Documentation", - value = "Documentation") -@Component("eu.xenit.apix.rest.v1.DocumentationWebscript") -@Authentication(AuthenticationType.USER) -public class DocumentationWebscript extends ApixV1Webscript {//implements BeanFactoryAware{ - - Logger logger = LoggerFactory.getLogger(DocumentationWebscript.class); - - private IVersionService versionService; - private IWebUtils webUtils; - - @Autowired - public DocumentationWebscript(IVersionService versionService, IWebUtils webUtils) { - this.versionService = versionService; - this.webUtils = webUtils; - } - - @Uri(value = "/swagger.json", method = HttpMethod.GET) - @ApiOperation("The Swagger Spec for Alfred API") - @ApiResponses(@ApiResponse(code = 200, message = "Success")) - public void execute(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) throws IOException { - webScriptResponse.setContentType("json"); - Swagger s = generateSwagger(); - Json.mapper().writeValue(webScriptResponse.getOutputStream(), s); - } - - @Uri(value = "/ui", method = HttpMethod.GET) - public void redirectToSwaggerUi(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) { - webScriptResponse.setStatus(302); - String swaggerUi = webScriptRequest.getServiceContextPath() + "/swagger/ui/"; - String servicePath = webScriptRequest.getServicePath(); - String swaggerJsonUrl = servicePath.substring(0, servicePath.lastIndexOf(47) + 1) + "swagger.json"; - webScriptResponse.setHeader("Location", swaggerUi + "?url=" + URLEncoder.encode(swaggerJsonUrl)); - } - - public Swagger generateSwagger() { - Reader r = new Reader(); - // Correctly sets QName, Noderef, etc because swagger reader doesnt understand - ModelConverters.getInstance().addConverter(new ModelConverter() { - @Override - public Property resolveProperty(Type type, ModelConverterContext context, Annotation[] annotations, - Iterator chain) { - if (chain.hasNext()) { - return chain.next().resolveProperty(type, context, annotations, chain); - } - return null; - } - - @Override - public Model resolve(Type type, ModelConverterContext context, Iterator chain) { - if (type instanceof SimpleType) { - Class cls = ((SimpleType) type).getRawClass();// No clue why this happens - - if (cls.equals(NodeRef.class)) { - ModelImpl noderefModel = new ModelImpl(); - noderefModel.setName("NodeRef"); - noderefModel.setType("string"); - noderefModel.setExample("workspace://SpacesStore/987-978-79-797-797-978"); - return noderefModel; - } - if (cls.equals(QName.class)) { - ModelImpl noderefModel = new ModelImpl(); - noderefModel.setName("QName"); - noderefModel.setType("string"); - noderefModel.setExample("{http://www.alfresco.org/model/content/1.0}content"); - return noderefModel; - } - } - - if (chain.hasNext()) { - return chain.next().resolve(type, context, chain); - } - return null; - } - }); - // Ignore special DE webscript - r.setIgnoredRoutes(new String[]{"/apix/v1/docs/ui"}); - - r.read(ApixSwaggerDescription.class); - r.read(BulkWebscript1.class); - r.read(CategoryWebScript1.class); - r.read(ConfigurationWebscript1.class); - r.read(DictionaryWebScript1.class); - r.read(DocumentationWebscript.class); - r.read(GeneralWebscript.class); - r.read(NodesWebscript1.class); - r.read(SearchWebScript1.class); - r.read(SitesWebscript1.class); - r.read(TranslationsWebscript1.class); - r.read(VersionHistoryWebScript1.class); - r.read(WIPWebscript.class); - r.read(WorkingcopiesWebscript1.class); - r.read(PeopleWebscript1.class); - r.read(PropertiesWebScript1.class); - r.read(eu.xenit.apix.rest.v2.people.PeopleWebscript.class); - r.read(eu.xenit.apix.rest.v2.groups.GroupsWebscript.class); - r.read(NodesWebscriptV2.class); - - addSwaggerUIOperation(r); - - r.getSwagger().getInfo().setVersion(versionService.getVersionDescription().getVersion()); - - r.getSwagger().setSchemes(getSchemes()); - r.getSwagger().setBasePath("/alfresco/s" + RestV1Config.ApixUrl); - Map paths = r.getSwagger().getPaths(); - HashMap newPaths = new HashMap<>(); - for (Map.Entry entry : paths.entrySet()) { - if (!entry.getKey().startsWith(RestV1Config.BaseUrl) && !entry.getKey().startsWith(RestV2Config.BaseUrl)) { - throw new RuntimeException( - "Extract an operation from a webscript which does not start with the BaseUrl: " - + entry.getKey()); - } - newPaths.put(entry.getKey().substring(RestV1Config.ApixUrl.length()), entry.getValue()); - } - r.getSwagger().setPaths(newPaths); - return r.getSwagger(); - } - - private void addSwaggerUIOperation(Reader r) { - Operation op = new Operation(); - Response response = new Response().description("Swagger UI interface"); - response.schema(new FileProperty()); - op.addResponse(String.valueOf(200), response); - op.tag("Documentation"); - Path p = new Path(); - op.setSummary("Shows this swagger spec in a user interface"); - p.setGet(op); - r.getSwagger().path("/apix/v1/docs/ui", p); - } - - public List getSchemes() { - ArrayList ret = new ArrayList<>(); - // This doesn't seem to work with the current setup at xenit, - // using https://xxx.dev.xenit.eu gives me http protocol instead of https - - // So, always use https - // Seems to work on 12/12/17, adding both. TODO: use from location instead of option - ret.add(Scheme.HTTPS); - ret.add(Scheme.HTTP); - return ret; - } -} +//package eu.xenit.apix.rest.v1; +// +//import com.fasterxml.jackson.databind.type.SimpleType; +//import eu.xenit.apix.data.NodeRef; +//import eu.xenit.apix.data.QName; +//import eu.xenit.apix.rest.v1.bulk.BulkWebscript1; +//import eu.xenit.apix.rest.v1.categories.CategoryWebScript1; +//import eu.xenit.apix.rest.v1.configuration.ConfigurationWebscript1; +//import eu.xenit.apix.rest.v1.dictionary.DictionaryWebScript1; +//import eu.xenit.apix.rest.v1.nodes.NodesWebscript1; +//import eu.xenit.apix.rest.v1.people.PeopleWebscript1; +//import eu.xenit.apix.rest.v1.properties.PropertiesWebScript1; +//import eu.xenit.apix.rest.v1.search.SearchWebScript1; +//import eu.xenit.apix.rest.v1.sites.SitesWebscript1; +//import eu.xenit.apix.rest.v1.temp.WIPWebscript; +//import eu.xenit.apix.rest.v1.translation.TranslationsWebscript1; +//import eu.xenit.apix.rest.v1.versionhistory.VersionHistoryWebScript1; +//import eu.xenit.apix.rest.v1.workingcopies.WorkingcopiesWebscript1; +//import eu.xenit.apix.rest.v2.RestV2Config; +//import eu.xenit.apix.rest.v2.nodes.NodesWebscriptV2; +//import eu.xenit.apix.version.IVersionService; +//import eu.xenit.apix.web.IWebUtils; +//import eu.xenit.swagger.reader.Reader; +//import io.swagger.annotations.ApiOperation; +//import io.swagger.annotations.ApiResponse; +//import io.swagger.annotations.ApiResponses; +//import io.swagger.converter.ModelConverter; +//import io.swagger.converter.ModelConverterContext; +//import io.swagger.converter.ModelConverters; +//import io.swagger.models.Model; +//import io.swagger.models.ModelImpl; +//import io.swagger.models.Operation; +//import io.swagger.models.Path; +//import io.swagger.models.Response; +//import io.swagger.models.Scheme; +//import io.swagger.models.Swagger; +//import io.swagger.models.properties.FileProperty; +//import io.swagger.models.properties.Property; +//import io.swagger.util.Json; +//import java.io.IOException; +//import java.lang.annotation.Annotation; +//import java.lang.reflect.Type; +//import java.util.ArrayList; +//import java.util.HashMap; +//import java.util.Iterator; +//import java.util.List; +//import java.util.Map; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.extensions.surf.util.URLEncoder; +//import org.springframework.extensions.webscripts.WebScriptRequest; +//import org.springframework.extensions.webscripts.WebScriptResponse; +//import org.springframework.stereotype.Component; +// +//@WebScript( +// baseUri = RestV1Config.BaseUrl + "/docs", +// families = {RestV1Config.Family}, +// defaultFormat = "json", +// description = "Access API Documentation", +// value = "Documentation") +//@Component("eu.xenit.apix.rest.v1.DocumentationWebscript") +//@Authentication(AuthenticationType.USER) +//public class DocumentationWebscript extends ApixV1Webscript {//implements BeanFactoryAware{ +// +// Logger logger = LoggerFactory.getLogger(DocumentationWebscript.class); +// +// private IVersionService versionService; +// private IWebUtils webUtils; +// +// @Autowired +// public DocumentationWebscript(IVersionService versionService, IWebUtils webUtils) { +// this.versionService = versionService; +// this.webUtils = webUtils; +// } +// +// @Uri(value = "/swagger.json", method = HttpMethod.GET) +// @ApiOperation("The Swagger Spec for Alfred API") +// @ApiResponses(@ApiResponse(code = 200, message = "Success")) +// public void execute(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) throws IOException { +// webScriptResponse.setContentType("json"); +// Swagger s = generateSwagger(); +// Json.mapper().writeValue(webScriptResponse.getOutputStream(), s); +// } +// +// @Uri(value = "/ui", method = HttpMethod.GET) +// public void redirectToSwaggerUi(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) { +// webScriptResponse.setStatus(302); +// String swaggerUi = webScriptRequest.getServiceContextPath() + "/swagger/ui/"; +// String servicePath = webScriptRequest.getServicePath(); +// String swaggerJsonUrl = servicePath.substring(0, servicePath.lastIndexOf(47) + 1) + "swagger.json"; +// webScriptResponse.setHeader("Location", swaggerUi + "?url=" + URLEncoder.encode(swaggerJsonUrl)); +// } +// +// public Swagger generateSwagger() { +// Reader r = new Reader(); +// // Correctly sets QName, Noderef, etc because swagger reader doesnt understand +// ModelConverters.getInstance().addConverter(new ModelConverter() { +// @Override +// public Property resolveProperty(Type type, ModelConverterContext context, Annotation[] annotations, +// Iterator chain) { +// if (chain.hasNext()) { +// return chain.next().resolveProperty(type, context, annotations, chain); +// } +// return null; +// } +// +// @Override +// public Model resolve(Type type, ModelConverterContext context, Iterator chain) { +// if (type instanceof SimpleType) { +// Class cls = ((SimpleType) type).getRawClass();// No clue why this happens +// +// if (cls.equals(NodeRef.class)) { +// ModelImpl noderefModel = new ModelImpl(); +// noderefModel.setName("NodeRef"); +// noderefModel.setType("string"); +// noderefModel.setExample("workspace://SpacesStore/987-978-79-797-797-978"); +// return noderefModel; +// } +// if (cls.equals(QName.class)) { +// ModelImpl noderefModel = new ModelImpl(); +// noderefModel.setName("QName"); +// noderefModel.setType("string"); +// noderefModel.setExample("{http://www.alfresco.org/model/content/1.0}content"); +// return noderefModel; +// } +// } +// +// if (chain.hasNext()) { +// return chain.next().resolve(type, context, chain); +// } +// return null; +// } +// }); +// // Ignore special DE webscript +// r.setIgnoredRoutes(new String[]{"/apix/v1/docs/ui"}); +// +// r.read(ApixSwaggerDescription.class); +// r.read(BulkWebscript1.class); +// r.read(CategoryWebScript1.class); +// r.read(ConfigurationWebscript1.class); +// r.read(DictionaryWebScript1.class); +// r.read(DocumentationWebscript.class); +// r.read(GeneralWebscript.class); +// r.read(NodesWebscript1.class); +// r.read(SearchWebScript1.class); +// r.read(SitesWebscript1.class); +// r.read(TranslationsWebscript1.class); +// r.read(VersionHistoryWebScript1.class); +// r.read(WIPWebscript.class); +// r.read(WorkingcopiesWebscript1.class); +// r.read(PeopleWebscript1.class); +// r.read(PropertiesWebScript1.class); +// r.read(eu.xenit.apix.rest.v2.people.PeopleWebscript.class); +// r.read(eu.xenit.apix.rest.v2.groups.GroupsWebscript.class); +// r.read(NodesWebscriptV2.class); +// +// addSwaggerUIOperation(r); +// +// r.getSwagger().getInfo().setVersion(versionService.getVersionDescription().getVersion()); +// +// r.getSwagger().setSchemes(getSchemes()); +// r.getSwagger().setBasePath("/alfresco/s" + RestV1Config.ApixUrl); +// Map paths = r.getSwagger().getPaths(); +// HashMap newPaths = new HashMap<>(); +// for (Map.Entry entry : paths.entrySet()) { +// if (!entry.getKey().startsWith(RestV1Config.BaseUrl) && !entry.getKey().startsWith(RestV2Config.BaseUrl)) { +// throw new RuntimeException( +// "Extract an operation from a webscript which does not start with the BaseUrl: " +// + entry.getKey()); +// } +// newPaths.put(entry.getKey().substring(RestV1Config.ApixUrl.length()), entry.getValue()); +// } +// r.getSwagger().setPaths(newPaths); +// return r.getSwagger(); +// } +// +// private void addSwaggerUIOperation(Reader r) { +// Operation op = new Operation(); +// Response response = new Response().description("Swagger UI interface"); +// response.schema(new FileProperty()); +// op.addResponse(String.valueOf(200), response); +// op.tag("Documentation"); +// Path p = new Path(); +// op.setSummary("Shows this swagger spec in a user interface"); +// p.setGet(op); +// r.getSwagger().path("/apix/v1/docs/ui", p); +// } +// +// public List getSchemes() { +// ArrayList ret = new ArrayList<>(); +// // This doesn't seem to work with the current setup at xenit, +// // using https://xxx.dev.xenit.eu gives me http protocol instead of https +// +// // So, always use https +// // Seems to work on 12/12/17, adding both. TODO: use from location instead of option +// ret.add(Scheme.HTTPS); +// ret.add(Scheme.HTTP); +// return ret; +// } +//} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java index 8946c65c..943eb352 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java @@ -1,43 +1,30 @@ package eu.xenit.apix.rest.v1; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.version.IVersionService; import eu.xenit.apix.version.VersionDescription; -import eu.xenit.apix.web.IWebUtils; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; -@WebScript(baseUri = RestV1Config.BaseUrl, families = {RestV1Config.Family}, defaultFormat = "json", - description = "General API operations", value = "General") -@Component("eu.xenit.apix.rest.v1.GeneralWebscript") -@Authentication(AuthenticationType.USER) -public class GeneralWebscript extends ApixV1Webscript {//implements BeanFactoryAware{ +//@WebScript(baseUri = RestV1Config.BaseUrl, families = {RestV1Config.Family}, defaultFormat = "json", +// description = "General API operations", value = "General") +//@Authentication(AuthenticationType.USER) +@RestController("eu.xenit.apix.rest.v1.GeneralWebscript") +public class GeneralWebscript extends ApixV1Webscript { - Logger logger = LoggerFactory.getLogger(GeneralWebscript.class); + private final IVersionService versionService; - IVersionService versionService; - - @Autowired - public GeneralWebscript(IVersionService versionService, IWebUtils webUtils) { + public GeneralWebscript(IVersionService versionService) { this.versionService = versionService; } - @Uri(value = "/version", method = HttpMethod.GET) + @GetMapping(value = "/v1/version") @ApiOperation("Access the version information for Api-X") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = VersionDescription.class)) - public void getApixVersion(WebScriptResponse response) throws IOException { - writeJsonResponse(response, versionService.getVersionDescription()); + public ResponseEntity getApixVersion() { + return writeJsonResponse(versionService.getVersionDescription()); } - } \ No newline at end of file diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java index abe81f64..79af9ff8 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java @@ -3,13 +3,7 @@ import com.fasterxml.jackson.core.io.JsonStringEncoder; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dynamicextensionsalfresco.webscripts.WebScriptUriRegistry; -import com.github.dynamicextensionsalfresco.webscripts.annotations.FormatStyle; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; @@ -22,70 +16,44 @@ import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.extensions.surf.util.Content; import org.springframework.extensions.surf.util.URLDecoder; +import org.springframework.extensions.webscripts.DeclarativeRegistry; import org.springframework.extensions.webscripts.Match; import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; /** * Created by kenneth on 18.03.16. Largely rewritten by roel on 13.03.18 */ -@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", - description = "Perform multiple operations in a single call", value = "Bulk") -@Component("eu.xenit.apix.rest.v1.BulkWebscript") +//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", +// description = "Perform multiple operations in a single call", value = "Bulk") +@RestController("eu.xenit.apix.rest.v1.BulkWebscript") public class BulkWebscript1 extends ApixV1Webscript { + private static final Logger logger = LoggerFactory.getLogger(BulkWebscript1.class); + private final ServiceRegistry serviceRegistry; + private final DeclarativeRegistry wsRegistry; - private final static Logger logger = LoggerFactory.getLogger(BulkWebscript1.class); - @Autowired - ServiceRegistry serviceRegistry; - // Dynamic Extensions is needed to provide the object that can be autowired in here - @Autowired - WebScriptUriRegistry wsuriRegistry; - - public BulkWebscript1() { - } - - public BulkWebscript1(ServiceRegistry serviceRegistry, WebScriptUriRegistry registry) { + public BulkWebscript1(ServiceRegistry serviceRegistry, + @Qualifier("webscripts.registry") DeclarativeRegistry wsRegistry) { this.serviceRegistry = serviceRegistry; - this.wsuriRegistry = registry; - } - - public static BulkSubResult createBulkResult(ObjectMapper mapper, IntermediateResponse resp) throws IOException { - int status = resp.getStatus(); - JsonNode body; - String strbody = resp.getWriter().toString(); - - if (strbody == null || strbody.equals("")) { - body = mapper.createObjectNode(); - } else { - body = mapper.readTree(resp.getWriter().toString()); - } - - return new BulkSubResult(status, body, resp.getHeaders()); - } - - public static BulkSubResult create404subResult(ObjectMapper mapper, String url) throws IOException { - return new BulkSubResult(HttpStatus.SC_NOT_FOUND /* = 404 */, - mapper.readTree("\"No Webscript found for url " + - new String(JsonStringEncoder.getInstance().quoteAsString(url)) + "\""), - new HashMap(0)); + this.wsRegistry = wsRegistry; } - @Uri(value = "/bulk", method = HttpMethod.POST, formatStyle = FormatStyle.ARGUMENT) + @PostMapping(value = "/v1/bulk") @ApiOperation("Performs multiple Api-X operations in a single rest call") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = BulkSubResult[].class)) - public void bulk(final BulkRequest[] bulkRequests, final WebScriptRequest req, final WebScriptResponse response) + public ResponseEntity bulk(@RequestBody final BulkRequest[] bulkRequests, final WebScriptRequest req) throws IOException { - final WebScriptUriRegistry registry = wsuriRegistry; final ObjectMapper mapper = new ObjectMapper(); final List bulkResults = new ArrayList<>(); - for (int i = 0; i < bulkRequests.length; i++) { - BulkRequest request = bulkRequests[i]; + for (BulkRequest request : bulkRequests) { // v1 bulk only gets to send to other v1 endpoints :( // We need to url decode this so we can find the match and parse any @UriVariable final String url = URLDecoder.decode("/apix/v1" + request.getUrl()); @@ -93,14 +61,14 @@ public void bulk(final BulkRequest[] bulkRequests, final WebScriptRequest req, f logger.debug("Evaluating {} with body {}", url, request.getBody()); String strippedUrl = url; - if(url.contains("?")) { + if (url.contains("?")) { strippedUrl = url.substring(0, url.indexOf("?")); } //The Match created in this method does not split off the querystring arguments correctly, //therefore we will remove the queryString from the url for this method. Later in the call, //the url with query string is still passed to have it handled. - final Match m = registry.findWebScript(request.getMethod(), strippedUrl); + final Match m = wsRegistry.findWebScript(request.getMethod(), strippedUrl); if (m == null || m.getWebScript() == null) { logger.debug("Could not find any webscript bound to {}. Injecting 404 subresponse.", url); @@ -108,7 +76,7 @@ public void bulk(final BulkRequest[] bulkRequests, final WebScriptRequest req, f continue; } - logger.debug("Matched on {}", m.getWebScript().getClass().toString()); + logger.debug("Matched on {}", m.getWebScript().getClass()); // These Intermediate... classes are simple container objects, standing in for HTTP requests and responses // They are used to execute the WebScript directly, providing arguments and retrieving the result @@ -120,23 +88,20 @@ public void bulk(final BulkRequest[] bulkRequests, final WebScriptRequest req, f // transaction as "needs to be rolled back". We don't want a previous subrequest to be rolled back because // the next subrequest used some exception-driven code. Also, please don't use exceptions as flow control. BulkSubResult subRes = (BulkSubResult) serviceRegistry.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - try { - // Actual execution of called WebScript happens here - m.getWebScript().execute(intermediateRequest, intermediateResponse); - logger.debug("Resp body is '{}'", intermediateResponse.getWriter().toString()); - // Convert the response container to json + statuscode + headers - return createBulkResult(mapper, intermediateResponse); - } catch (Exception e) { - // Catching all exceptions to just print a stacktrace isn't super clean... - // But we want the bulk to continue with the other requests even if this one fails. - logger.error("Error in bulk call to " + url, e); - return new BulkSubResult(500, - new ObjectMapper().valueToTree("Exception found: " + e.getMessage()), - new HashMap()); - } + .doInTransaction((RetryingTransactionHelper.RetryingTransactionCallback) () -> { + try { + // Actual execution of called WebScript happens here + m.getWebScript().execute(intermediateRequest, intermediateResponse); + logger.debug("Resp body is '{}'", intermediateResponse.getWriter().toString()); + // Convert the response container to json + statuscode + headers + return createBulkResult(mapper, intermediateResponse); + } catch (Exception e) { + // Catching all exceptions to just print a stacktrace isn't super clean... + // But we want the bulk to continue with the other requests even if this one fails. + logger.error("Error in bulk call to {}", url, e); + return new BulkSubResult(500, + new ObjectMapper().valueToTree("Exception found: " + e.getMessage()), + new HashMap<>()); } }, false, true); @@ -149,9 +114,30 @@ public Object execute() throws Throwable { if (bulkResults.size() > 0) { // Write out the list of BulkSubResults which becomes nice json - writeJsonResponse(response, bulkResults); + return writeJsonResponse(bulkResults); + } + logger.warn("No results for bulk operation"); + return ResponseEntity.noContent().build(); + } + + private static BulkSubResult createBulkResult(ObjectMapper mapper, IntermediateResponse resp) throws IOException { + int status = resp.getStatus(); + JsonNode body; + String strbody = resp.getWriter().toString(); + + if (strbody == null || strbody.equals("")) { + body = mapper.createObjectNode(); } else { - logger.warn("No results for bulk operation"); + body = mapper.readTree(resp.getWriter().toString()); } + + return new BulkSubResult(status, body, resp.getHeaders()); + } + + private static BulkSubResult create404subResult(ObjectMapper mapper, String url) throws IOException { + return new BulkSubResult(HttpStatus.SC_NOT_FOUND /* = 404 */, + mapper.readTree("\"No Webscript found for url " + + new String(JsonStringEncoder.getInstance().quoteAsString(url)) + "\""), + new HashMap<>(0)); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateContent.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateContent.java index e22875ca..7e10bedf 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateContent.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateContent.java @@ -5,6 +5,8 @@ import java.io.InputStream; import java.io.Reader; import java.io.StringReader; +import java.nio.charset.StandardCharsets; + import org.apache.commons.io.IOUtils; import org.springframework.extensions.surf.util.Content; @@ -43,7 +45,7 @@ public long getSize() { @Override public InputStream getInputStream() { - return IOUtils.toInputStream(json); + return IOUtils.toInputStream(json, StandardCharsets.UTF_8); } @Override diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateResponse.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateResponse.java index d214d831..80ec79b8 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateResponse.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateResponse.java @@ -65,6 +65,11 @@ public void reset() { // not supported } + @Override + public void reset(String preserveHeadersPattern) { + // not supported + } + public void setCache(Cache cache) { // not supported } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java index 95a5fd78..06bd79bb 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java @@ -1,44 +1,36 @@ package eu.xenit.apix.rest.v1.categories; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.categories.Category; import eu.xenit.apix.categories.ICategoryService; import eu.xenit.apix.data.QName; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; -@WebScript(baseUri = RestV1Config.BaseUrl + "/category", families = RestV1Config.Family, defaultFormat = "json", - description = "Retrieves Category information", value = "Category") -@Authentication(AuthenticationType.USER) -@Component("eu.xenit.apix.rest.v1.categories.CategoryWebScript1") +//@WebScript(baseUri = RestV1Config.BaseUrl + "/category", families = RestV1Config.Family, defaultFormat = "json", +// description = "Retrieves Category information", value = "Category") +//@Authentication(AuthenticationType.USER) +@RestController("eu.xenit.apix.rest.v1.categories.CategoryWebScript1") public class CategoryWebScript1 extends ApixV1Webscript { - Logger logger = LoggerFactory.getLogger(CategoryWebScript1.class); - @Autowired - private ICategoryService categoryService; + private final ICategoryService categoryService; - @Uri(value = "/aspect/{qname}", method = HttpMethod.GET) - @ApiOperation(value = "Return the categories available for an aspect", notes = "") + public CategoryWebScript1(ICategoryService categoryService) { + this.categoryService = categoryService; + } + + @GetMapping(value = "/v1/category/aspect/{qname}") + @ApiOperation(value = "Return the categories available for an aspect") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Categories.class)) - public void getCategoriesForAspect(@UriVariable final String qname, WebScriptResponse webScriptResponse) - throws IOException { + public ResponseEntity getCategoriesForAspect(@PathVariable final String qname) { QName apixQName = new QName(qname); List categories = categoryService.getCategoryTree(apixQName); - writeJsonResponse(webScriptResponse, new Categories(categories)); + return writeJsonResponse(new Categories(categories)); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java index 2da850c0..f64bea26 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java @@ -3,72 +3,66 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.ExceptionHandler; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; -import com.sun.star.auth.InvalidArgumentException; import eu.xenit.apix.configuration.ConfigurationFileFlags; import eu.xenit.apix.configuration.ConfigurationService; import eu.xenit.apix.configuration.Configurations; -import eu.xenit.apix.content.IContentService; -import eu.xenit.apix.filefolder.IFileFolderService; -import eu.xenit.apix.node.INodeService; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; import java.io.IOException; -import java.io.Writer; import java.util.Arrays; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; - -@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", - description = "Retrieves configuration data files from the datadictionary", value = "Configuration") -@Authentication(AuthenticationType.USER) -@Component("eu.xenit.apix.rest.v1.configuration.ConfigurationWebscript1") +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", +// description = "Retrieves configuration data files from the datadictionary", value = "Configuration") +//@Authentication(AuthenticationType.USER) +@RestController("eu.xenit.apix.rest.v1.configuration.ConfigurationWebscript1") public class ConfigurationWebscript1 extends ApixV1Webscript { private static final Logger log = LoggerFactory.getLogger(ConfigurationWebscript1.class); - @Autowired - IFileFolderService fileFolderService; - - @Autowired - INodeService nodeService; + private final ObjectMapper mapper; - @Autowired - IContentService contentService; - @Autowired - ConfigurationService configurationService; + private final ConfigurationService configurationService; + public ConfigurationWebscript1( + @Qualifier("eu.xenit.apix.configuration.ConfigurationService") ConfigurationService configurationService) { + this.configurationService = configurationService; + mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false); + } - @Uri(value = "/configuration", method = HttpMethod.GET, defaultFormat = "json") + @GetMapping(value = "/v1/configuration", consumes = {"application/js"}, produces = {"application/js"}) @ApiOperation("Returns configuration files information and content") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Configurations.class)) - - public void getConfigurationFiles( - @RequestParam(defaultValue = "content,nodeRef", delimiter = ",") @ApiParam(value = "Comma separated field names to include.", defaultValue = "content,nodeRef", allowableValues = "content,nodeRef,path,metadata,parsedContent") String[] fields, - @RequestParam @ApiParam("The directory to search for configuration files, relative to the data dictionary") String searchDirectory, - @RequestParam(value = "filter.name", required = false) @ApiParam(name = "filter.name", value = "Regular expression that the node name should match.") String nameFilter, - @RequestParam(required = false) @ApiParam("Javascript callback function") String callback, - WebScriptRequest webScriptRequest, - WebScriptResponse webScriptResponse + public ResponseEntity getJsConfigurationFiles( + @RequestParam(defaultValue = "content,nodeRef", required = false) + @ApiParam( + value = "Comma separated field names to include.", + defaultValue = "content,nodeRef", + allowableValues = "content,nodeRef,path,metadata,parsedContent") String[] fields, + @RequestParam @ApiParam("The directory to search for configuration files, relative to the data dictionary") + String searchDirectory, + @RequestParam(value = "filter.name", required = false) + @ApiParam(name = "filter.name", value = "Regular expression that the node name should match.") + String nameFilter, + @RequestParam(required = false) @ApiParam("Javascript callback function") String callback ) throws IOException { List fieldsList = Arrays.asList(fields); ConfigurationFileFlags configurationFileFlags = new ConfigurationFileFlags( @@ -79,35 +73,62 @@ public void getConfigurationFiles( fieldsList.contains("nodeRef")); Configurations configurations = configurationService .getConfigurationFiles(searchDirectory, nameFilter, configurationFileFlags); - - if (webScriptRequest.getFormat().equalsIgnoreCase("js")) { - writeJsResponse(callback, webScriptResponse, configurations); - } else { - writeJsonResponse(webScriptResponse, configurations); - } + return ResponseEntity.ok() + .body( + String.format("%s(%s)", callback, + mapper.writeValueAsString(configurations))); +// webScriptResponse.setContentEncoding("utf-8"); +// webScriptResponse.setHeader("Cache-Control", "no-cache"); +// +// if (webScriptRequest.getFormat().equalsIgnoreCase("js")) { +// webScriptResponse.setContentType("application/js"); +// try(Writer writer = webScriptResponse.getWriter()) { +// writer.write(callback); +// writer.write("("); +// mapper.writeValue(writer, configurations); +// writer.write(");"); +// writer.flush(); +// } +// return; +// } } - private void writeJsResponse(String callback, WebScriptResponse webScriptResponse, Configurations configurations) - throws IOException { - webScriptResponse.setContentType("application/js"); - webScriptResponse.setContentEncoding("utf-8"); - webScriptResponse.setHeader("Cache-Control", "no-cache"); - Writer writer = webScriptResponse.getWriter(); - writer.write(callback); - writer.write("("); - ObjectMapper mapper = new ObjectMapper(); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false); - mapper.writeValue(writer, configurations); - writer.write(");"); - writer.flush(); - writer.close(); + + @GetMapping(value = "/v1/configuration" , + consumes = {MediaType.APPLICATION_JSON_VALUE}, + produces = {MediaType.APPLICATION_JSON_VALUE}) + @ApiOperation("Returns configuration files information and content") + @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Configurations.class)) + public ResponseEntity getConfigurationFiles( + @RequestParam(defaultValue = "content,nodeRef", required = false) + @ApiParam( + value = "Comma separated field names to include.", + defaultValue = "content,nodeRef", + allowableValues = "content,nodeRef,path,metadata,parsedContent") + String[] fields, + @RequestParam + @ApiParam("The directory to search for configuration files, relative to the data dictionary") + String searchDirectory, + @RequestParam(value = "filter.name", required = false) + @ApiParam(name = "filter.name", value = "Regular expression that the node name should match.") + String nameFilter + ) throws IOException { + List fieldsList = Arrays.asList(fields); + ConfigurationFileFlags configurationFileFlags = new ConfigurationFileFlags( + fieldsList.contains("content"), + fieldsList.contains("path"), + fieldsList.contains("parsedContent"), + fieldsList.contains("metadata"), + fieldsList.contains("nodeRef")); + Configurations configurations = configurationService + .getConfigurationFiles(searchDirectory, nameFilter, configurationFileFlags); + return ResponseEntity.ok() + .body(configurations); } @ExceptionHandler(IllegalArgumentException.class) - private void writeBadRequestResponse(IllegalArgumentException exception, WebScriptResponse response) throws IOException{ - log.debug("Bad input;", exception); - response.setStatus(400); - writeJsonResponse(response, exception.getMessage()); + private ResponseEntity writeBadRequestResponse(IllegalArgumentException exception) { + log.debug("Bad input", exception); + return ResponseEntity.badRequest().body(exception.getMessage()); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java index 61904866..fce351df 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java @@ -1,13 +1,5 @@ package eu.xenit.apix.rest.v1.dictionary; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.FormatStyle; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.data.QName; import eu.xenit.apix.dictionary.IDictionaryService; import eu.xenit.apix.dictionary.aspects.AspectDefinition; @@ -18,109 +10,110 @@ import eu.xenit.apix.properties.Properties; import eu.xenit.apix.properties.PropertyDefinition; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; -import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; - -@WebScript(baseUri = RestV1Config.BaseUrl + "/dictionary", families = RestV1Config.Family, defaultFormat = "json", - description = "Retrieves Dictionary information", value = "Dictionary") -@Authentication(AuthenticationType.USER) -@Component("eu.xenit.apix.rest.v1.property.DictionaryWebScript1") +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +//@WebScript(baseUri = RestV1Config.BaseUrl + "/dictionary", families = RestV1Config.Family, defaultFormat = "json", +// description = "Retrieves Dictionary information", value = "Dictionary") +//@Authentication(AuthenticationType.USER) +@RestController("eu.xenit.apix.rest.v1.property.DictionaryWebScript1") public class DictionaryWebScript1 extends ApixV1Webscript { - Logger logger = LoggerFactory.getLogger(DictionaryWebScript1.class); - @Autowired - IDictionaryService dictionaryService; + private static final Logger logger = LoggerFactory.getLogger(DictionaryWebScript1.class); + private final IDictionaryService dictionaryService; + public DictionaryWebScript1( + @Qualifier(("eu.xenit.apix.dictionary.IDictionaryService")) IDictionaryService dictionaryService) { + this.dictionaryService = dictionaryService; + } - @Uri(value = "/properties/{qname}", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT) - @ApiOperation(value = "Return the definition of a property", notes = "") + @GetMapping(value = "/v1/dictionary/properties/**") + @ApiOperation(value = "Return the definition of a property") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = PropertyDefinition.class)) - public void getPropertyDefinition(@UriVariable final String qname, WebScriptResponse webScriptResponse) - throws IOException { - eu.xenit.apix.data.QName apixQName = new eu.xenit.apix.data.QName(qname); - PropertyDefinition propDef = dictionaryService.GetPropertyDefinition(apixQName); + public ResponseEntity getPropertyDefinition(HttpServletRequest request) { + QName qname = extractQNameFromUrlPath(request, "/v1/dictionary/properties/"); + PropertyDefinition propDef = dictionaryService.GetPropertyDefinition(qname); if (propDef == null) { - webScriptResponse.setStatus(HttpStatus.SC_NOT_FOUND); + return ResponseEntity.notFound().build(); } - writeJsonResponse(webScriptResponse, propDef); + return writeJsonResponse(propDef); } - - @Uri(value = "/properties", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT) - @ApiOperation(value = "Return properties", notes = "") + @GetMapping(value = "/v1/dictionary/properties") + @ApiOperation(value = "Return properties") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Properties.class)) - public void getProperties( - WebScriptResponse webScriptResponse) throws IOException { - Properties properties = dictionaryService.getProperties(); - writeJsonResponse(webScriptResponse, properties); + public ResponseEntity getProperties() { + return writeJsonResponse(dictionaryService.getProperties()); } - @Uri(value = "/types", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT) - @ApiOperation(value = "Return the definitions of types", notes = "") + @GetMapping(value = "/v1/dictionary/types") + @ApiOperation(value = "Return the definitions of types") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Types.class)) - public void getSubTypeDefinitions(@RequestParam(defaultValue = "sys:base", required = false) final String parent, - WebScriptResponse webScriptResponse) throws IOException { - QName apixQName = new QName(parent); - Types types = dictionaryService.GetSubTypeDefinitions(apixQName, true); - writeJsonResponse(webScriptResponse, types); + public ResponseEntity getSubTypeDefinitions(@RequestParam(defaultValue = "sys:base", required = false) + final String parent) { + return writeJsonResponse( + dictionaryService.GetSubTypeDefinitions( + new QName(parent), true + ) + ); } - @Uri(value = "/types/{qname}", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT) - @ApiOperation(value = "Return the definition of a type", notes = "") + @GetMapping(value = "/v1/dictionary/types/**") + @ApiOperation(value = "Return the definition of a type") @ApiResponses({ @ApiResponse(code = 200, message = "Success", response = TypeDefinition.class), @ApiResponse(code = 404, message = "Not Found")}) - public void getTypeDefinition(@UriVariable final String qname, WebScriptResponse webScriptResponse) - throws IOException { - logger.debug("Received type qname %s", qname); - eu.xenit.apix.data.QName apixQName = new eu.xenit.apix.data.QName(qname); - TypeDefinition classDef = dictionaryService.GetTypeDefinition(apixQName); + public ResponseEntity getTypeDefinition(HttpServletRequest request) { + QName qname = extractQNameFromUrlPath(request, "/v1/dictionary/types/"); + logger.debug("Received type qname {}", qname); + TypeDefinition classDef = dictionaryService.GetTypeDefinition(qname); if (classDef == null) { - webScriptResponse.setStatus(HttpStatus.SC_NOT_FOUND); + return ResponseEntity.notFound().build(); } - writeJsonResponse(webScriptResponse, classDef); + return writeJsonResponse(classDef); } - @Uri(value = "/aspects/{qname}", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT) - @ApiOperation(value = "Return the definition of a aspect", notes = "") + @GetMapping(value = "/v1/dictionary/aspects/**") + @ApiOperation(value = "Return the definition of a aspect") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = AspectDefinition.class)) - public void getAspectDefinition(@UriVariable final String qname, WebScriptResponse webScriptResponse) - throws IOException { - logger.debug("Received aspect qname %s", qname); - eu.xenit.apix.data.QName apixQName = new eu.xenit.apix.data.QName(qname); - AspectDefinition classDef = dictionaryService.GetAspectDefinition(apixQName); + public ResponseEntity getAspectDefinition(HttpServletRequest request) { + QName qname = extractQNameFromUrlPath(request, "/v1/dictionary/aspects/"); + logger.debug("Received aspect qname {}", qname); + AspectDefinition classDef = dictionaryService.GetAspectDefinition(qname); if (classDef == null) { - webScriptResponse.setStatus(HttpStatus.SC_NOT_FOUND); + return ResponseEntity.notFound().build(); } - writeJsonResponse(webScriptResponse, classDef); + return writeJsonResponse(classDef); } - @Uri(value = "/aspects", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT) - @ApiOperation(value = "Return apects", notes = "") + @GetMapping(value = "/v1/dictionary/aspects") + @ApiOperation(value = "Return apects") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Aspects.class)) - public void getAspects(WebScriptResponse webScriptResponse) throws IOException { - Aspects aspects = dictionaryService.getAspects(); - writeJsonResponse(webScriptResponse, aspects); + public ResponseEntity getAspects() { + return writeJsonResponse(dictionaryService.getAspects()); } - @Uri(value = "/namespaces", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT) - @ApiOperation(value = "Returns the namespaces", notes = "") + @GetMapping(value = "/v1/dictionary/namespaces") + @ApiOperation(value = "Returns the namespaces") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Namespaces.class)) - public void getNamespaces(WebScriptResponse webScriptResponse) throws IOException { - Namespaces namespaces = dictionaryService.getNamespaces(); - writeJsonResponse(webScriptResponse, namespaces); + public ResponseEntity getNamespaces() { + return writeJsonResponse(dictionaryService.getNamespaces()); } - + private QName extractQNameFromUrlPath(HttpServletRequest request, String path) { + String qnameValue = request.getRequestURI().split(request.getContextPath() + path)[1]; + return new QName(qnameValue); + } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/internal/ApixArgumentResolver.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/internal/ApixArgumentResolver.java index bf04c99e..6e777336 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/internal/ApixArgumentResolver.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/internal/ApixArgumentResolver.java @@ -1,47 +1,48 @@ -package eu.xenit.apix.rest.v1.internal; +// TODO @Zlatin FIXME Alfresco MVC to be tested -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dynamicextensionsalfresco.webscripts.arguments.ArgumentResolver; -import java.io.IOException; -import java.lang.annotation.Annotation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; - -/** - * Created by Michiel Huygen on 14/03/2016. - */ -@Component -public class ApixArgumentResolver implements ArgumentResolver { - - private Logger logger = LoggerFactory.getLogger(ApixArgumentResolver.class); - - @Override - public final boolean supports(final Class parameterType, final Class annotationType) { - /* Determine if using Class.isAssignableFrom() breaks backwards compatibility. */ - return parameterType.getCanonicalName().startsWith("eu.xenit.apix") && !Exception.class.isAssignableFrom(parameterType); - } - - @Override - public final Object resolveArgument(final Class argumentType, final Annotation parameterAnnotation, - final String name, final WebScriptRequest request, final WebScriptResponse response) { - /*final Class expectedParameterType = getExpectedArgumentType(); - if (argumentType.equals(expectedParameterType) == false) { - throw new IllegalArgumentException(String.format("Incorrect parameter type %s, expected type %s", - argumentType, expectedParameterType)); - }*/ - - try { - //TODO: inject apix object mapper? - ObjectMapper map = new ObjectMapper(); - return map.readValue(request.getContent().getContent(), argumentType); - } catch (IOException e) { - logger.warn("Cannot convert webscript argument with type from package eu.xenit.apix to json", e); - throw new RuntimeException("Cannot convert webscript argument (" + name + ") " + - "with type from package eu.xenit.apix to json - " + argumentType.getCanonicalName(), e); - } - } - -} +//package eu.xenit.apix.rest.v1.internal; +// +//import com.fasterxml.jackson.databind.ObjectMapper; +//import java.io.IOException; +//import java.lang.annotation.Annotation; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.springframework.extensions.webscripts.WebScriptRequest; +//import org.springframework.extensions.webscripts.WebScriptResponse; +//import org.springframework.stereotype.Component; +// +///** +// * Created by Michiel Huygen on 14/03/2016. +// */ +//@Component +//public class ApixArgumentResolver implements ArgumentResolver { +// +// private Logger logger = LoggerFactory.getLogger(ApixArgumentResolver.class); +// +// @Override +// public final boolean supports(final Class parameterType, final Class annotationType) { +// /* Determine if using Class.isAssignableFrom() breaks backwards compatibility. */ +// return parameterType.getCanonicalName().startsWith("eu.xenit.apix") && !Exception.class.isAssignableFrom(parameterType); +// } +// +// @Override +// public final Object resolveArgument(final Class argumentType, final Annotation parameterAnnotation, +// final String name, final WebScriptRequest request, final WebScriptResponse response) { +// /*final Class expectedParameterType = getExpectedArgumentType(); +// if (argumentType.equals(expectedParameterType) == false) { +// throw new IllegalArgumentException(String.format("Incorrect parameter type %s, expected type %s", +// argumentType, expectedParameterType)); +// }*/ +// +// try { +// //TODO: inject apix object mapper? +// ObjectMapper map = new ObjectMapper(); +// return map.readValue(request.getContent().getContent(), argumentType); +// } catch (IOException e) { +// logger.warn("Cannot convert webscript argument with type from package eu.xenit.apix to json", e); +// throw new RuntimeException("Cannot convert webscript argument (" + name + ") " + +// "with type from package eu.xenit.apix to json - " + argumentType.getCanonicalName(), e); +// } +// } +// +//} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeAclsOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeAclsOptions.java index 1cc69fdd..805ac025 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeAclsOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeAclsOptions.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.Set; @@ -10,11 +9,9 @@ public class ChangeAclsOptions { private boolean inheritFromParent; private Set ownAccessList; - private ObjectMapper mapper = new ObjectMapper(); - @JsonCreator public ChangeAclsOptions(@JsonProperty("inheritFromParent") boolean inheritFromParent, - @JsonProperty("ownAccessList") Set ownAccessList) throws IOException { + @JsonProperty("ownAccessList") Set ownAccessList) { this.ownAccessList = ownAccessList; this.inheritFromParent = inheritFromParent; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java index 1e85bc16..119bce8c 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java @@ -7,7 +7,7 @@ class InheritFromParent { @ApiModelProperty(required = true) - public boolean inheritFromParent; + private boolean inheritFromParent; @JsonCreator public InheritFromParent(@JsonProperty("inheritFromParent") boolean inheritFromParent) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java index 209f1e1c..74b61040 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java @@ -1,13 +1,7 @@ package eu.xenit.apix.rest.v1.nodes; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dynamicextensionsalfresco.webscripts.annotations.ExceptionHandler; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Transaction; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.comments.Comment; import eu.xenit.apix.comments.Conversation; import eu.xenit.apix.comments.ICommentService; @@ -27,7 +21,6 @@ import eu.xenit.apix.permissions.NodePermission; import eu.xenit.apix.permissions.PermissionValue; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import eu.xenit.apix.rest.v1.nodes.ChangeAclsOptions.Access; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @@ -35,64 +28,60 @@ import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; import java.io.IOException; -import java.io.InputStream; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import org.alfresco.model.ContentModel; -import org.alfresco.repo.model.Repository; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.security.PermissionService; -import org.apache.commons.io.IOUtils; import org.apache.http.HttpStatus; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.InputStreamResource; import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.extensions.webscripts.WrappingWebScriptResponse; import org.springframework.extensions.webscripts.servlet.FormData; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; -@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", - description = "Access operations on nodes", value = "Nodes") -@Transaction(readOnly = false) -@Component("eu.xenit.apix.rest.v1.NodesWebscript") +//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", +// description = "Access operations on nodes", value = "Nodes") +//@Transaction(readOnly = false) +@RestController("eu.xenit.apix.rest.v1.NodesWebscript") public class NodesWebscript1 extends ApixV1Webscript { - private final static Logger logger = LoggerFactory.getLogger(NodesWebscript1.class); + private static final Logger logger = LoggerFactory.getLogger(NodesWebscript1.class); - @Autowired - INodeService nodeService; + private final INodeService nodeService; - @Autowired - IPermissionService permissionService; + private final IPermissionService permissionService; - @Autowired - IFileFolderService fileFolderService; + private final IFileFolderService fileFolderService; - @Autowired - ICommentService commentService; + private final ICommentService commentService; - @Autowired - ServiceRegistry serviceRegistry; + private final ServiceRegistry serviceRegistry; - @Autowired - Repository repository; + public NodesWebscript1(INodeService nodeService, IPermissionService permissionService, + IFileFolderService fileFolderService, ICommentService commentService, + ServiceRegistry serviceRegistry) { + this.nodeService = nodeService; + this.permissionService = permissionService; + this.fileFolderService = fileFolderService; + this.commentService = commentService; + this.serviceRegistry = serviceRegistry; + } - @Uri(value = "/nodes/{space}/{store}/{guid}/metadata", method = HttpMethod.POST) + @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/metadata") @ApiOperation(value = "Change node metadata", notes = "Example to set a node's title and add the sys:versionable aspect:\n" + "\n" + @@ -120,220 +109,213 @@ public class NodesWebscript1 extends ApixV1Webscript { "}\n" + "```\n" + "\n" + - "Changing the cm:name property will also update the qname path of the node so it is in sync with it.\n" + "Changing the cm:name property will also update the qname path " + + "of the node so it is in sync with it.\n" + - "This only applies to nodes of type or subtype cm:content or cm:folder but not of type or subtype of cm:systemfolder.") + "This only applies to nodes of type or subtype cm:content or cm:folder " + + "but not of type or subtype of cm:systemfolder.") @ApiResponses({ @ApiResponse(code = 200, message = "Success", response = NodeMetadata.class), @ApiResponse(code = 403, message = "Not Authorized") }) - public void setMetadata(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, - final MetadataChanges changes, final WebScriptResponse response) throws IOException { + public ResponseEntity setMetadata(@PathVariable final String space, @PathVariable final String store, + @PathVariable final String guid, @RequestBody final MetadataChanges changes) { NodeRef nodeRef = createNodeRef(space, store, guid); NodeMetadata nodeMetadata = nodeService.setMetadata(nodeRef, changes); if (nodeMetadata == null) { - response.setStatus(404); + ResponseEntity.notFound(); } - writeJsonResponse(response, nodeMetadata); - + return writeJsonResponse(nodeMetadata); } @ApiOperation("Retrieve node metadata") - @Uri(value = "/nodes/{space}/{store}/{guid}/metadata", method = HttpMethod.GET) + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/metadata") @ApiResponses({ @ApiResponse(code = 200, message = "Success", response = NodeMetadata.class), @ApiResponse(code = 403, message = "Not Authorized") }) - public void getMetadata(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptResponse response) throws IOException { - - NodeRef nodeRef = this.createNodeRef(space, store, guid); - NodeMetadata nodeMetadata = nodeService.getMetadata(nodeRef); + public ResponseEntity getMetadata(@PathVariable String space, @PathVariable String store, + @PathVariable String guid) { + NodeMetadata nodeMetadata = nodeService.getMetadata( + this.createNodeRef(space, store, guid) + ); if (nodeMetadata == null) { - response.setStatus(404); + return ResponseEntity.notFound().build(); } else { - writeJsonResponse(response, nodeMetadata); + return writeJsonResponse(nodeMetadata); } - } @ApiOperation("Delete a node") - @Uri(value = "/nodes/{space}/{store}/{guid}", method = HttpMethod.DELETE) + @DeleteMapping(value = "/v1/nodes/{space}/{store}/{guid}") @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized"), @ApiResponse(code = 404, message = "Not Found")}) - public void deleteNode(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, - @RequestParam(required = false) final String permanently, final WebScriptResponse response) - throws IOException { - logger.debug(" permanently: " + permanently); + public ResponseEntity deleteNode(@PathVariable final String space, @PathVariable final String store, + @PathVariable final String guid, + @RequestParam(required = false) final String permanently) { + logger.debug(" permanently: {}", permanently); boolean deletePermanently = permanently != null && permanently.equals("true"); - logger.debug(" deletePermanently: " + deletePermanently); + logger.debug(" deletePermanently: {}", deletePermanently); NodeRef nodeRef = createNodeRef(space, store, guid); - boolean success = nodeService.deleteNode(nodeRef, deletePermanently); - if (success) { + if (nodeService.deleteNode(nodeRef, deletePermanently)) { logger.debug("node {} deleted", nodeRef); - response.setStatus(200); - writeJsonResponse(response, "Node deleted."); - } else { - logger.debug("Failed to delete node, node does not exist: {}", nodeRef); - response.setStatus(404); - writeJsonResponse(response, "Failed to delete node, node does not exist: " + nodeRef.toString()); + return ResponseEntity.ok("Node deleted."); } - + logger.debug("Failed to delete node, node does not exist: {}", nodeRef); + return ResponseEntity + .status(HttpStatus.SC_NOT_FOUND) + .body(String.format("Failed to delete node, node does not exist: %s", nodeRef.toString())); } - @ApiOperation("Retrieve node associations.\nVersionstore does not support sourceAssocs. For version nodes, an empty list is returned for this component of the result.") - @Uri(value = "/nodes/{space}/{store}/{guid}/associations", method = HttpMethod.GET) + @ApiOperation("Retrieve node associations.\n" + + "Versionstore does not support sourceAssocs. " + + "For version nodes, an empty list is returned for this component of the result.") + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations") @ApiResponses({@ApiResponse(code = 200, message = "Success", response = NodeAssociations.class), @ApiResponse(code = 403, message = "Not Authorized")}) - public void getAssociations(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptResponse response) throws IOException { - NodeRef nodeRef = this.createNodeRef(space, store, guid); - NodeAssociations associations = this.nodeService.getAssociations(nodeRef); - writeJsonResponse(response, associations); - + public ResponseEntity getAssociations(@PathVariable String space, @PathVariable String store, + @PathVariable String guid) { + return writeJsonResponse( + this.nodeService.getAssociations( + this.createNodeRef(space, store, guid) + ) + ); } @ApiOperation("Create new association with given node as source") - @Uri(value = "/nodes/{space}/{store}/{guid}/associations", method = HttpMethod.POST) + @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations") @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) - public void createAssociation(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - CreateAssociationOptions options, - WebScriptResponse response) throws IOException { - NodeRef source = this.createNodeRef(space, store, guid); - nodeService.createAssociation(source, options.getTarget(), options.getType()); - - //writeJsonResponse(response, associations); - response.setStatus(200); + public ResponseEntity createAssociation(@PathVariable String space, @PathVariable String store, + @PathVariable String guid, + @RequestBody CreateAssociationOptions options) { + nodeService.createAssociation( + this.createNodeRef(space, store, guid), + options.getTarget(), + options.getType() + ); + return ResponseEntity.ok().build(); } @ApiOperation("Deletes an association with given node as source") - @Uri(value = "/nodes/{space}/{store}/{guid}/associations", method = HttpMethod.DELETE) + @DeleteMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations") @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) - public void deleteAssociation(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - @RequestParam String target, @RequestParam String type, - WebScriptResponse response) throws IOException { - NodeRef source = this.createNodeRef(space, store, guid); - NodeRef targetNode = new NodeRef(URLDecoder.decode(target, StandardCharsets.UTF_8.toString())); - - nodeService.removeAssociation(source, - targetNode, - new QName(type)); - response.setStatus(200); - + public ResponseEntity deleteAssociation(@PathVariable String space, @PathVariable String store, + @PathVariable String guid, @RequestParam NodeRef target, + @RequestParam String type) { + nodeService.removeAssociation( + this.createNodeRef(space, store, guid), + target, + new QName(type) + ); + return ResponseEntity.ok().build(); } @ApiOperation("Retrieve node parent associations") - @Uri(value = "/nodes/{space}/{store}/{guid}/associations/parents", method = HttpMethod.GET) + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations/parents") @ApiResponses({@ApiResponse(code = 200, message = "Success", response = ChildParentAssociation[].class), @ApiResponse(code = 403, message = "Not Authorized")}) - public void getParentAssociations(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptResponse response) throws IOException { - NodeRef nodeRef = this.createNodeRef(space, store, guid); - - List associations = this.nodeService.getParentAssociations(nodeRef); - - writeJsonResponse(response, associations); - + public ResponseEntity> getParentAssociations(@PathVariable String space, + @PathVariable String store, + @PathVariable String guid) { + return writeJsonResponse( + this.nodeService.getParentAssociations( + this.createNodeRef(space, store, guid) + ) + ); } @ApiOperation("Retrieve node child associations") - @Uri(value = "/nodes/{space}/{store}/{guid}/associations/children", method = HttpMethod.GET) + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations/children") @ApiResponses({@ApiResponse(code = 200, message = "Success", response = ChildParentAssociation[].class), @ApiResponse(code = 403, message = "Not Authorized")}) - public void getChildAssociations(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptResponse response) throws IOException { - NodeRef nodeRef = this.createNodeRef(space, store, guid); - - List associations = this.nodeService.getChildAssociations(nodeRef); - - writeJsonResponse(response, associations); - + public ResponseEntity> getChildAssociations(@PathVariable String space, + @PathVariable String store, + @PathVariable String guid) { + return writeJsonResponse( + this.nodeService.getChildAssociations( + this.createNodeRef(space, store, guid) + ) + ); } @ApiOperation("Retrieve node peer associations with given node being the source") - @Uri(value = "/nodes/{space}/{store}/{guid}/associations/targets", method = HttpMethod.GET) + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations/targets") @ApiResponses({@ApiResponse(code = 200, message = "Success", response = NodeAssociation[].class), @ApiResponse(code = 403, message = "Not Authorized")}) - public void getSourcePeerAssociations(@UriVariable String space, @UriVariable String store, - @UriVariable String guid, - WebScriptResponse response) throws IOException { - NodeRef nodeRef = this.createNodeRef(space, store, guid); - - List associations = this.nodeService.getTargetAssociations(nodeRef); - - writeJsonResponse(response, associations); - + public ResponseEntity> getSourcePeerAssociations(@PathVariable String space, + @PathVariable String store, + @PathVariable String guid) { + return writeJsonResponse( + this.nodeService.getTargetAssociations( + this.createNodeRef(space, store, guid) + ) + ); } @ApiOperation(value = "Retrieve current user's permissions for a node", notes = "Returns a key-value map of permissions keys to a value of 'DENY' or 'ALLOW'. " + "Possible keys are: Read, Write, Delete, CreateChildren, ReadPermissions, ChangePermissions, " + "or custom permissions") - @Uri(value = "/nodes/{space}/{store}/{guid}/permissions", method = HttpMethod.GET) + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/permissions") @ApiResponses({ @ApiResponse(code = 200, message = "Success", response = PermissionValue.class, responseContainer = "Map")}) // It would seem permissions can always be retrieved? - public void getPermissions(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptResponse response) throws IOException { - NodeRef nodeRef = this.createNodeRef(space, store, guid); - - Map permissions = this.permissionService.getPermissions(nodeRef); - writeJsonResponse(response, permissions); - + public ResponseEntity> getPermissions(@PathVariable String space, + @PathVariable String store, + @PathVariable String guid) { + return writeJsonResponse( + this.permissionService.getPermissions( + this.createNodeRef(space, store, guid) + ) + ); } @ApiOperation(value = "sets a user a permission for a node.") - @Uri(value = "/nodes/{space}/{store}/{guid}/permissions/authority/{authority}/permission/{permission}", method = HttpMethod.POST) + @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/permissions/authority/{authority}/permission/{permission}") @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) - public void setPermission(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - @UriVariable String authority, @UriVariable String permission, WebScriptResponse response) - throws IOException { - NodeRef nodeRef = this.createNodeRef(space, store, guid); - - this.permissionService.setPermission(nodeRef, authority, permission); - response.setStatus(200); - + public ResponseEntity setPermission(@PathVariable String space, @PathVariable String store, + @PathVariable String guid, @PathVariable String authority, + @PathVariable String permission) { + this.permissionService.setPermission( + this.createNodeRef(space, store, guid), authority, permission + ); + return ResponseEntity.ok().build(); } @ApiOperation(value = "removes a user its permission for a node.") - @Uri(value = "/nodes/{space}/{store}/{guid}/permissions/authority/{authority}/permission/{permission}", method = HttpMethod.DELETE) + @DeleteMapping(value = "/v1/nodes/{space}/{store}/{guid}/permissions/authority/{authority}/permission/{permission}") @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) - public void deletePermission(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - @UriVariable String authority, @UriVariable String permission, WebScriptResponse response) - throws IOException { - NodeRef nodeRef = this.createNodeRef(space, store, guid); - - this.permissionService.deletePermission(nodeRef, authority, permission); - response.setStatus(200); - + public ResponseEntity deletePermission(@PathVariable String space, @PathVariable String store, + @PathVariable String guid, @PathVariable String authority, + @PathVariable String permission) { + this.permissionService.deletePermission(this.createNodeRef(space, store, guid), authority, permission); + return ResponseEntity.ok().build(); } @ApiOperation(value = "Gets the ACLs for a node.") - @Uri(value = "/nodes/{space}/{store}/{guid}/acl", method = HttpMethod.GET) + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/acl") @ApiResponses({@ApiResponse(code = 200, message = "Success", response = NodePermission.class), @ApiResponse(code = 403, message = "Not Authorized")}) - public void getAcls(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptResponse response) throws IOException { - NodeRef nodeRef = this.createNodeRef(space, store, guid); - - NodePermission permissions = this.permissionService.getNodePermissions(nodeRef); - response.setStatus(200); - writeJsonResponse(response, permissions); - + public ResponseEntity getAcls(@PathVariable String space, @PathVariable String store, + @PathVariable String guid) { + return writeJsonResponse( + this.permissionService.getNodePermissions( + this.createNodeRef(space, store, guid) + ) + ); } - @Uri(value = "/nodes/{space}/{store}/{guid}/acl/inheritFromParent", method = HttpMethod.POST) + @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/acl/inheritFromParent") @ApiResponses({@ApiResponse(code = 403, message = "Not Authorized")}) - public void setInheritParentPermissions(@UriVariable String space, @UriVariable String store, - @UriVariable String guid, final InheritFromParent inherit) { - NodeRef nodeRef = this.createNodeRef(space, store, guid); - this.permissionService.setInheritParentPermissions(nodeRef, inherit.inheritFromParent); + public void setInheritParentPermissions(@PathVariable String space, @PathVariable String store, + @PathVariable String guid, @RequestBody final InheritFromParent inherit) { + this.permissionService.setInheritParentPermissions( + this.createNodeRef(space, store, guid), inherit.isInheritFromParent() + ); } @ApiOperation(value = "Sets the ACL for a node.", notes = "Example:\n" + @@ -349,22 +331,18 @@ public void setInheritParentPermissions(@UriVariable String space, @UriVariable " }\n" + "]}\n" + "```", consumes = "application/json") - @Uri(value = "/nodes/{space}/{store}/{guid}/acl", method = HttpMethod.PUT) + @PutMapping(value = "/v1/nodes/{space}/{store}/{guid}/acl") @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) - public void setAcls(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - final ChangeAclsOptions changeAclsOptions, WebScriptRequest request, WebScriptResponse response) - throws JSONException, IOException { - NodeRef nodeRef = this.createNodeRef(space, store, guid); - + public ResponseEntity setAcls(@PathVariable String space, @PathVariable String store, + @PathVariable String guid, + @RequestBody final ChangeAclsOptions changeAclsOptions) { NodePermission permissions = new NodePermission(); - permissions.setInheritFromParent(changeAclsOptions.isInheritFromParent()); Set accessList = new HashSet<>(); permissions.setOwnAccessList(accessList); Set ownAccessList = changeAclsOptions.getOwnAccessList(); if (ownAccessList == null) { - response.setStatus(400); - return; + return ResponseEntity.badRequest().build(); } for (Access access : changeAclsOptions.getOwnAccessList()) { NodePermission.Access a = new NodePermission.Access(); @@ -373,52 +351,55 @@ public void setAcls(@UriVariable String space, @UriVariable String store, @UriVa a.setAuthority(access.authority); a.setPermission(access.permission); } - this.permissionService.setNodePermissions(nodeRef, permissions); - - response.setStatus(200); - + this.permissionService.setNodePermissions( + this.createNodeRef(space, store, guid), permissions + ); + return ResponseEntity.ok().build(); } @ApiOperation("Returns path of the node") - @Uri(value = "/nodes/{space}/{store}/{guid}/path", method = HttpMethod.GET) + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/path") @ApiResponses({@ApiResponse(code = 200, message = "Success", response = NodePath.class), @ApiResponse(code = 403, message = "Not Authorized")}) - public void getPath(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptResponse response) throws IOException { - NodeRef nodeRef = this.createNodeRef(space, store, guid); - - NodePath path = this.fileFolderService.getPath(nodeRef); - writeJsonResponse(response, path); - - } - - @ApiOperation("Returns combined information of a node.\nNote: versionstore does not support sourceAssocs. For version nodes, an empty list added to the result") - @Uri(value = "/nodes/{space}/{store}/{guid}", method = HttpMethod.GET) + public ResponseEntity getPath(@PathVariable String space, @PathVariable String store, + @PathVariable String guid) { + return writeJsonResponse( + this.fileFolderService.getPath( + this.createNodeRef(space, store, guid) + ) + ); + } + + @ApiOperation("Returns combined information of a node.\n" + + "Note: versionstore does not support sourceAssocs. " + + "For version nodes, an empty list added to the result") + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}") @ApiResponses({ @ApiResponse(code = 200, message = "Success", response = NodeInfo.class), @ApiResponse(code = 403, message = "Not Authorized"), @ApiResponse(code = 404, message = "Not Found") }) - public void getAllInfoOfNode(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptResponse response) throws IOException { - NodeRef nodeRef = this.createNodeRef(space, store, guid); - + public ResponseEntity getAllInfoOfNode(@PathVariable String space, @PathVariable String store, + @PathVariable String guid) { try { // This method will return a null result if user has insufficient permissions - NodeInfo nodeInfo = this - .nodeRefToNodeInfo(nodeRef, this.fileFolderService, this.nodeService, this.permissionService); + NodeInfo nodeInfo = this.nodeRefToNodeInfo( + this.createNodeRef(space, store, guid), + this.fileFolderService, this.nodeService, this.permissionService + ); if (nodeInfo != null) { - writeJsonResponse(response, nodeInfo); - } else { - String message = String.format("Insufficient permissions for node %s", nodeRef); - throw new AccessDeniedException(message); + return writeJsonResponse(nodeInfo); } + return ResponseEntity + .status(HttpStatus.SC_UNAUTHORIZED) + .body(String.format("Insufficient permissions for node %s://%s/%s", space, store, guid)); } catch (InvalidNodeRefException invalidNodeRefException) { - logger.debug("Failed to get node info, node does not exist: {}", invalidNodeRefException); - response.setStatus(404); - writeJsonResponse(response, "Failed to get node info, node does not exist."); + logger.debug("Failed to get node info, node does not exist: {}://{}/{}", space, store, guid, + invalidNodeRefException); + return ResponseEntity + .status(HttpStatus.SC_NOT_FOUND) + .body("Failed to get node info, node does not exist."); } - } @ApiOperation(value = "Returns combined information of multiple nodes. " @@ -443,36 +424,32 @@ public void getAllInfoOfNode(@UriVariable String space, @UriVariable String stor "]}\n" + "```" + "\n" + - "'retrieveMetadata', 'retrievePath', 'retrievePermissions', 'retrieveAssocs', 'retrieveChildAssocs',\n" + "'retrieveMetadata', 'retrievePath', 'retrievePermissions', " + + "'retrieveAssocs', 'retrieveChildAssocs',\n" + "'retrieveParentAssocs', 'retrieveTargetAssocs' are optional parameters.\n" + "Set 'retrieveMetadata' to false to omit the aspects and properties from the result.\n" + "Set 'retrievePath' to false to omit the path from the result.\n" + "Set 'retrievePermissions' to false to omit the permissions from the result.\n" + - "Set 'retrieveAssocs' to false to omit the associations(parent associations, child associations, peer associations) from the result.\n" + "Set 'retrieveAssocs' to false to omit the associations(parent associations, child associations, " + + "peer associations) from the result.\n" + "Set 'retrieveChildAssocs' to false to omit the child associations from the result.\n" + "Set 'retrieveParentAssocs' to false to omit the parent associations from the result.\n" + "Set 'retrieveTargetAssocs' to false to omit the peer target associations from the result.\n" + - "Set 'retrieveSourceAssocs' to false to omit the peer source associations from the result. Note: versionstore does not support sourceAssocs. For version nodes, an empty list added to the result\n") - @Uri(value = "/nodes/nodeInfo", method = HttpMethod.POST) + "Set 'retrieveSourceAssocs' to false to omit the peer source associations from the result. " + + "Note: versionstore does not support sourceAssocs. " + + "For version nodes, an empty list added to the result\n") + @PostMapping(value = "/v1/nodes/nodeInfo") @ApiResponses({ @ApiResponse(code = 200, message = "Success", response = NodeInfo[].class), @ApiResponse(code = 400, message = "Bad Request") }) - public void getAllInfoOfNodes(WebScriptRequest request, WebScriptResponse response) - throws IOException, JSONException { - String requestString = request.getContent().getContent(); - logger.debug("request content: " + requestString); + // TODO @Zlatin MVC Pojo + public ResponseEntity getAllInfoOfNodes(@RequestBody final String requestString) { + logger.debug("request content: {}", requestString); JSONObject jsonObject = new JSONObject(requestString); - if (jsonObject == null) { - response.setStatus(400); - String message = String - .format("Malfromed body: request string could not be parsed to jsonObject: %s", requestString); - logger.debug(message); - writeJsonResponse(response, message); - } - logger.debug("json: " + jsonObject.toString()); + logger.debug("json: {}", jsonObject); boolean retrieveMetadata = true; boolean retrievePath = true; @@ -483,7 +460,7 @@ public void getAllInfoOfNodes(WebScriptRequest request, WebScriptResponse respon boolean retrieveTargetAssocs = true; boolean retrieveSourceAssocs = true; - List nodeRefs = new ArrayList(); + List nodeRefs = new ArrayList<>(); try { if (jsonObject.has("retrieveMetadata")) { retrieveMetadata = jsonObject.getBoolean("retrieveMetadata"); @@ -511,29 +488,19 @@ public void getAllInfoOfNodes(WebScriptRequest request, WebScriptResponse respon } JSONArray nodeRefsJsonArray = jsonObject.getJSONArray("noderefs"); - if (nodeRefsJsonArray == null) { - response.setStatus(400); - String message = String.format("Could not retrieve target noderefs from body: %s", jsonObject); - logger.debug(message); - writeJsonResponse(response, message); - } int nodeRefsJsonArrayLength = nodeRefsJsonArray.length(); - logger.debug("nodeRefsJsonArrayLength: " + nodeRefsJsonArrayLength); + logger.debug("nodeRefsJsonArrayLength: {}", nodeRefsJsonArrayLength); for (int i = 0; i < nodeRefsJsonArrayLength; i++) { String nodeRefString = (String) nodeRefsJsonArray.get(i); - logger.debug("nodeRefString: " + nodeRefString); + logger.debug("nodeRefString: {}", nodeRefString); NodeRef nodeRef = new NodeRef(nodeRefString); nodeRefs.add(nodeRef); } } catch (JSONException e) { logger.error("Error deserializing json body", e); - String message = String.format("Malformed json body {}", jsonObject); - response.setStatus(400); - writeJsonResponse(response, message); + return ResponseEntity.badRequest().build(); } - //logger.error("done parsing request data"); - //logger.error("start nodeRefToNodeInfo"); List nodeInfoList = this.nodeRefToNodeInfo(nodeRefs, this.fileFolderService, this.nodeService, @@ -546,22 +513,20 @@ public void getAllInfoOfNodes(WebScriptRequest request, WebScriptResponse respon retrieveParentAssocs, retrieveTargetAssocs, retrieveSourceAssocs); - //logger.error("end nodeRefToNodeInfo"); - //logger.error("start writeJsonResponse"); - writeJsonResponse(response, nodeInfoList); - //logger.error("end writeJsonResponse"); + return writeJsonResponse(nodeInfoList); } @ApiOperation(value = "Retrieves the ancestors of the nodes", notes = "It is possible to add \"root\" as a request parameter.\n" + "It is the node reference up to which point ancestors will be retrieved.\n" + "The default root reference will be the reference of Company Home") - @Uri(value = "/nodes/{space}/{store}/{guid}/ancestors", method = HttpMethod.GET) + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/ancestors") @ApiResponses({@ApiResponse(code = 200, message = "Success", response = AncestorsObject.class), @ApiResponse(code = 403, message = "Not Authorized")}) - public void retrieveAncestors(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - @RequestParam(required = false) String root, WebScriptResponse response) throws IOException { + public ResponseEntity retrieveAncestors(@PathVariable String space, @PathVariable String store, + @PathVariable String guid, + @RequestParam(required = false) String root) { NodeRef nodeRef = this.createNodeRef(space, store, guid); NodeRef rootRef = null; if (root != null) { @@ -571,15 +536,15 @@ public void retrieveAncestors(@UriVariable String space, @UriVariable String sto try { List ancestors = nodeService.getAncestors(nodeRef, rootRef); AncestorsObject ancestorsObject = new AncestorsObject(nodeRef, ancestors); - writeJsonResponse(response, ancestorsObject); + return writeJsonResponse(ancestorsObject); } catch (InvalidNodeRefException ex) { - logger.error("noderef does not exist"); - response.setStatus(HttpStatus.SC_NOT_FOUND); - writeJsonResponse(response, ex.getMessage()); + logger.error("noderef does not exist", ex); + return ResponseEntity.status(HttpStatus.SC_NOT_FOUND) + .body(ex.getMessage()); } catch (AccessDeniedException ex) { - logger.error("access denied on noderef"); - response.setStatus(HttpStatus.SC_FORBIDDEN); - writeJsonResponse(response, ex.getMessage()); + logger.error("access denied on noderef", ex); + return ResponseEntity.status(HttpStatus.SC_FORBIDDEN) + .body(ex.getMessage()); } } @@ -614,89 +579,83 @@ public void retrieveAncestors(@UriVariable String space, @UriVariable String sto + "```" + "\n" + "\"aspectsToRemove\" is only relevant when copying a node.\n") - @Uri(value = "/nodes", method = HttpMethod.POST) + @PostMapping(value = "/v1/nodes") @ApiResponses({@ApiResponse(code = 200, message = "Success", response = NodeInfo.class), @ApiResponse(code = 403, message = "Not Authorized")}) - public void createNode(final CreateNodeOptions createNodeOptions, WebScriptResponse response) throws IOException { + public ResponseEntity createNode(@RequestBody final CreateNodeOptions createNodeOptions) { try { Object resultObject = serviceRegistry.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - NodeRef parent = new NodeRef(createNodeOptions.parent); - - if (!nodeService.exists(parent)) { - writeNotFoundResponse(response, parent); - return null; - } + .doInTransaction(() -> { + NodeRef parent = new NodeRef(createNodeOptions.parent); - NodeRef nodeRef; - NodeRef copyFrom = null; - if (createNodeOptions.copyFrom == null) { - nodeRef = nodeService - .createNode(parent, createNodeOptions.name, - new QName(createNodeOptions.type)); - } else { - copyFrom = new NodeRef(createNodeOptions.copyFrom); - if (!nodeService.exists(copyFrom)) { - response.setStatus(HttpStatus.SC_NOT_FOUND); - writeJsonResponse(response, "CopyFrom does not exist"); - return null; - } - nodeRef = nodeService.copyNode(copyFrom, parent, true); - } + if (!nodeService.exists(parent)) { + return writeNotFoundResponse(parent); + } - MetadataChanges metadataChanges; - QName type; - if (createNodeOptions.type != null) { - type = new QName(createNodeOptions.type); - } else if (createNodeOptions.type == null && createNodeOptions.copyFrom != null) { - type = nodeService.getMetadata(copyFrom).type; - } else { - response.setStatus(HttpStatus.SC_BAD_REQUEST); - writeJsonResponse(response, - "Please provide parameter \"type\" when creating a new node"); - return null; + NodeRef nodeRef; + NodeRef copyFrom = null; + if (createNodeOptions.copyFrom == null) { + nodeRef = nodeService + .createNode(parent, createNodeOptions.name, + new QName(createNodeOptions.type)); + } else { + copyFrom = new NodeRef(createNodeOptions.copyFrom); + if (!nodeService.exists(copyFrom)) { + return writeNotFoundResponse(copyFrom); } + nodeRef = nodeService.copyNode(copyFrom, parent, true); + } - metadataChanges = new MetadataChanges(type, - createNodeOptions.aspectsToAdd, - createNodeOptions.aspectsToRemove, - createNodeOptions.properties); - nodeService.setMetadata(nodeRef, metadataChanges); - - return nodeRef; + MetadataChanges metadataChanges; + QName type; + if (createNodeOptions.getType() != null) { + type = new QName(createNodeOptions.getType()); + } else if (createNodeOptions.getType() == null && createNodeOptions.getCopyFrom() != null) { + type = nodeService.getMetadata(copyFrom).type; + } else { + return ResponseEntity.status(HttpStatus.SC_BAD_REQUEST) + .body("Please provide parameter \"type\" when creating a new node"); } + + metadataChanges = new MetadataChanges(type, + createNodeOptions.aspectsToAdd, + createNodeOptions.aspectsToRemove, + createNodeOptions.properties); + nodeService.setMetadata(nodeRef, metadataChanges); + + return nodeRef; }, false, true); if (resultObject == null) { - return; + return ResponseEntity.internalServerError().build(); } NodeRef resultRef = new NodeRef(resultObject.toString()); NodeInfo nodeInfo = this .nodeRefToNodeInfo(resultRef, this.fileFolderService, this.nodeService, this.permissionService); - writeJsonResponse(response, nodeInfo); + return writeJsonResponse(nodeInfo); } catch (org.alfresco.service.cmr.model.FileExistsException fileExistsException) { throw new FileExistsException( new NodeRef(createNodeOptions.copyFrom), new NodeRef(fileExistsException.getParentNodeRef().toString()), fileExistsException.getName()); } - } @ApiOperation("Moves a node by changing its parent") - @Uri(value = "/nodes/{space}/{store}/{guid}/parent", method = HttpMethod.PUT) + @PutMapping(value = "/v1/nodes/{space}/{store}/{guid}/parent") @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) - public void setParent(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, final ChangeParentOptions location, WebScriptResponse response) - throws IOException { - NodeRef parent = new NodeRef(location.parent); + public ResponseEntity setParent(@PathVariable final String space, @PathVariable final String store, + @PathVariable final String guid, @RequestBody ChangeParentOptions location) { NodeRef nodeToMove = createNodeRef(space, store, guid); try { - nodeService.moveNode(nodeToMove, parent); + return ResponseEntity.ok( + nodeService.moveNode( + nodeToMove, + new NodeRef(location.getParent()) + ) + ); } catch (org.alfresco.service.cmr.model.FileExistsException fileExistsException) { throw new FileExistsException( nodeToMove, @@ -706,255 +665,195 @@ public void setParent(@UriVariable final String space, @UriVariable final String } @ApiOperation(value = "Retrieves all comments for a given node") - @Uri(value = "/nodes/{space}/{store}/{guid}/comments", method = HttpMethod.GET) + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/comments") @ApiResponses({ @ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized"), @ApiResponse(code = 404, message = "Not Found") }) - public void getComments(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - @RequestParam(defaultValue = "0") int skipcount, @RequestParam(defaultValue = "10") int pagesize, - WebScriptResponse response) throws IOException { + public ResponseEntity getComments(@PathVariable String space, @PathVariable String store, + @PathVariable String guid, @RequestParam(defaultValue = "0") int skipcount, + @RequestParam(defaultValue = "10") int pagesize) { final NodeRef target = this.createNodeRef(space, store, guid); - if (nodeService.exists(target)) { - if (permissionService.hasPermission(target, PermissionService.READ)) { - Conversation comments = commentService.getComments(target, skipcount, pagesize); - boolean canCreate = permissionService.hasPermission(target, PermissionService.CREATE_CHILDREN); - comments.setCreatable(canCreate); - response.setStatus(HttpStatus.SC_OK); - writeJsonResponse(response, comments); - } else { - throw new AccessDeniedException("User does not have permission to read parent node"); - } - } else { - writeNotFoundResponse(response, target); + if (!nodeService.exists(target)) { + return writeNotFoundResponse(target); + } + if (permissionService.hasPermission(target, PermissionService.READ)) { + Conversation comments = commentService.getComments(target, skipcount, pagesize); + boolean canCreate = permissionService.hasPermission(target, PermissionService.CREATE_CHILDREN); + comments.setCreatable(canCreate); + return writeJsonResponse(comments); } + return writeNotAuthorizedResponse(new AccessDeniedException(target.getValue())); } @ApiOperation(value = "Appends a new comment to the given node.") - @Uri(value = "/nodes/{space}/{store}/{guid}/comments", method = HttpMethod.POST) + @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/comments") @ApiResponses({ @ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized"), @ApiResponse(code = 404, message = "Not Found") }) - public void addComment(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - final Comment newComment, WebScriptRequest request, WebScriptResponse response) throws IOException { - final NodeRef target = new NodeRef(space, store, guid); - if (nodeService.exists(target)) { - Comment responseComment = commentService.addNewComment(target, newComment.getContent()); - response.setStatus(HttpStatus.SC_OK); - writeJsonResponse(response, responseComment); - } else { - writeNotFoundResponse(response, target); + public ResponseEntity addComment(@PathVariable String space, @PathVariable String store, + @PathVariable String guid, @RequestBody final Comment newComment) { + final NodeRef target = this.createNodeRef(space, store, guid); + if (!nodeService.exists(target)) { + return writeNotFoundResponse(target); } + Comment responseComment = commentService.addNewComment(target, newComment.getContent()); + return writeJsonResponse(responseComment); } @ApiOperation(value = "Returns the comment with the given id.") - @Uri(value = "/comments/{space}/{store}/{guid}", - method = HttpMethod.GET) + @GetMapping(value = "/v1/comments/{space}/{store}/{guid}") @ApiResponses({ @ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized"), @ApiResponse(code = 404, message = "Not Found") }) - public void getComment(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptRequest request, WebScriptResponse response) throws IOException { - final NodeRef targetComment = new NodeRef(space, store, guid); - if (nodeService.exists(targetComment)) { - if (permissionService.hasPermission(targetComment, PermissionService.READ)) { - Comment comment = commentService.getComment(targetComment); - response.setStatus(HttpStatus.SC_OK); - writeJsonResponse(response, comment); - } else { - throw new AccessDeniedException(String.format("User does not have permission " + - "to read the comment node %s", targetComment.toString())); - } + public ResponseEntity getComment(@PathVariable String space, @PathVariable String store, + @PathVariable String guid) { + final NodeRef targetComment = this.createNodeRef(space, store, guid); + if (!nodeService.exists(targetComment)) { + return writeNotFoundResponse(targetComment); + } + if (permissionService.hasPermission(targetComment, PermissionService.READ)) { + return writeJsonResponse(commentService.getComment(targetComment)); } else { - writeNotFoundResponse(response, targetComment); + throw new AccessDeniedException(String.format("User does not have permission " + + "to read the comment node %s", targetComment.toString())); } } @ApiOperation(value = "Updates the comment with the given id.") - @Uri(value = "/comments/{space}/{store}/{guid}", - method = HttpMethod.PUT) + @PutMapping(value = "/v1/comments/{space}/{store}/{guid}") @ApiResponses({ @ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized"), @ApiResponse(code = 404, message = "Not Found") }) - public void updateComment(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - final Comment newComment, WebScriptRequest request, WebScriptResponse response) throws IOException { - final NodeRef targetComment = new NodeRef(space, store, guid); - if (nodeService.exists(targetComment)) { - Comment updatedComment = commentService.updateComment(targetComment, newComment.getContent()); - response.setStatus(HttpStatus.SC_OK); - writeJsonResponse(response, updatedComment); - } else { - writeNotFoundResponse(response, targetComment); + public ResponseEntity updateComment(@PathVariable String space, @PathVariable String store, + @PathVariable String guid, @RequestBody final Comment newComment) { + final NodeRef targetComment = this.createNodeRef(space, store, guid); + if (!nodeService.exists(targetComment)) { + return writeNotFoundResponse(targetComment); } + Comment updatedComment = commentService.updateComment(targetComment, newComment.getContent()); + return writeJsonResponse(updatedComment); } @ApiOperation(value = "Deletes the comment with the given id.") - @Uri(value = "/comments/{space}/{store}/{guid}", - method = HttpMethod.DELETE) + @DeleteMapping(value = "/v1/comments/{space}/{store}/{guid}") @ApiResponses({ @ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized"), @ApiResponse(code = 404, message = "Not Found") }) - public void deleteComment(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptRequest request, WebScriptResponse response) throws IOException { - final NodeRef targetComment = new NodeRef(space, store, guid); - if (nodeService.exists(targetComment)) { - commentService.deleteComment(targetComment); - response.setStatus(HttpStatus.SC_OK); - writeJsonResponse(response, String.format("Comment %s deleted", targetComment.toString())); - } else { - writeNotFoundResponse(response, targetComment); + public ResponseEntity deleteComment(@PathVariable String space, @PathVariable String store, + @PathVariable String guid) { + final NodeRef targetComment = this.createNodeRef(space, store, guid); + if (!nodeService.exists(targetComment)) { + return writeNotFoundResponse(targetComment); } + commentService.deleteComment(targetComment); + return writeJsonResponse(String.format("Comment %s deleted", targetComment)); } @ApiOperation(value = "Downloads content file for given node") - @Uri(value = "/nodes/{space}/{store}/{guid}/content", method = HttpMethod.GET) + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/content") @ApiResponses({ @ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized"), @ApiResponse(code = 404, message = "Not Found")}) - public void getContent(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptResponse response) throws IOException { - final NodeRef nodeRef = new NodeRef(space, store, guid); + public ResponseEntity getContent(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { + final NodeRef nodeRef = this.createNodeRef(space, store, guid); ContentInputStream contentInputStream = nodeService.getContent(nodeRef); if (contentInputStream == null) { - response.setStatus(404); - return; - } - response.setContentType(contentInputStream.getMimetype()); - response.addHeader("Content-Length", Objects.toString(contentInputStream.getSize())); - - // Unwrap the webscript responses, because we don't want any caching when writing the file - WebScriptResponse resp = response; - while (resp instanceof WrappingWebScriptResponse) { - resp = ((WrappingWebScriptResponse) resp).getNext(); - } - - InputStream inputStream = contentInputStream.getInputStream(); - - try { - IOUtils.copyLarge(inputStream, resp.getOutputStream()); - } finally { - IOUtils.closeQuietly(inputStream); + return writeNotFoundResponse(nodeRef); } + return ResponseEntity.ok() + .body(new InputStreamResource(contentInputStream.getInputStream())); } - @ApiOperation(value = "Sets or updates the content for given node. If no file is given the content will be set to empty.", consumes = "multipart/form-data") - @Uri(value = "/nodes/{space}/{store}/{guid}/content", method = HttpMethod.PUT) + @ApiOperation(value = "Sets or updates the content for given node. " + + "If no file is given the content will be set to empty.", consumes = "multipart/form-data") + @PutMapping(value = "/v1/nodes/{space}/{store}/{guid}/content") @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) - @ApiImplicitParams({@ApiImplicitParam(name = "file", paramType = "form", dataType = "file", required = false)}) - public void setContent(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - final WebScriptRequest multiPart, WebScriptResponse response) throws IOException { + @ApiImplicitParams({@ApiImplicitParam(name = "file", paramType = "form", dataType = "file")}) + public ResponseEntity setContent(@PathVariable String space, @PathVariable String store, + @PathVariable String guid, @RequestPart final MultipartFile file) { final NodeRef finalDestination = this.createNodeRef(space, store, guid); RetryingTransactionHelper transactionHelper = serviceRegistry.getRetryingTransactionHelper(); - - org.springframework.extensions.webscripts.servlet.FormData.FormField content = null; - - org.springframework.extensions.webscripts.servlet.FormData formData = (org.springframework.extensions.webscripts.servlet.FormData) multiPart - .parseContent(); - final org.springframework.extensions.webscripts.servlet.FormData.FormField[] fields = formData.getFields(); - for (org.springframework.extensions.webscripts.servlet.FormData.FormField field : fields) { - if (field.getName().equals("file") && field.getIsFile()) { - content = field; - } - } - - final org.springframework.extensions.webscripts.servlet.FormData.FormField finalContent = content; - transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - - nodeService - .setContent(finalDestination, finalContent != null ? finalContent.getInputStream() : null, - finalContent != null ? finalContent.getFilename() : null); - return null; - } + transactionHelper.doInTransaction(() -> { + nodeService + .setContent(finalDestination, file != null ? file.getInputStream() : null, + file != null ? file.getOriginalFilename() : null); + return null; }, false, true); - - //writeJsonResponse(response, new Message("Successfully set content")); - + return ResponseEntity.ok().build(); } @ApiOperation(value = "Sets the content for given node to empty") - @Uri(value = "/nodes/{space}/{store}/{guid}/content", method = HttpMethod.DELETE) + @DeleteMapping(value = "/v1/nodes/{space}/{store}/{guid}/content") @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) - public void deleteContent(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - final WebScriptRequest multiPart, WebScriptResponse response) throws IOException { + public ResponseEntity deleteContent(@PathVariable String space, @PathVariable String store, + @PathVariable String guid) { RetryingTransactionHelper transactionHelper = serviceRegistry.getRetryingTransactionHelper(); final NodeRef finalDestination = this.createNodeRef(space, store, guid); - transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - - nodeService.setContent(finalDestination, null, null); - return null; - } + transactionHelper.doInTransaction(() -> { + nodeService.setContent(finalDestination, null, null); + return null; }, false, true); - + return ResponseEntity.ok().build(); } @ApiOperation(value = "Checks if the given node exists") - @Uri(value = "/nodes/{space}/{store}/{guid}/exists", method = HttpMethod.GET) + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/exists") @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) - public void exists(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptResponse response) throws IOException { - NodeRef nodeRef = new NodeRef(space, store, guid); - writeJsonResponse(response, nodeService.exists(nodeRef)); - + public ResponseEntity exists(@PathVariable String space, @PathVariable String store, + @PathVariable String guid) { + return writeJsonResponse( + nodeService.exists( + this.createNodeRef(space, store, guid) + ) + ); } @ApiOperation(value = "Creates a new node with given content", consumes = "multipart/form-data") - @Uri(value = "/nodes/upload", method = HttpMethod.POST) + @PostMapping(value = "/v1/nodes/upload") @ApiResponses({@ApiResponse(code = 200, message = "Success", response = NodeInfo.class), @ApiResponse(code = 403, message = "Not Authorized")}) @ApiImplicitParams({ - @ApiImplicitParam(value = "Noderef of parent for the new node", name = "parent", paramType = "form", dataType = "string", required = true), + @ApiImplicitParam(value = "Noderef of parent for the new node", name = "parent", paramType = "form", + dataType = "string", required = true), //TODO: Datatype doesnt work here? - @ApiImplicitParam(value = "QName type for the new node", name = "type", paramType = "form", dataType = "string", required = false), + @ApiImplicitParam(value = "QName type for the new node", name = "type", paramType = "form", + dataType = "string"), @ApiImplicitParam(name = "file", paramType = "form", dataType = "file", required = true), - @ApiImplicitParam(value = "Metadata for this file", name = "metadata", paramType = "form", dataType = "string", required = false), - @ApiImplicitParam(value = "Enable metadata extraction from the content, for example for msg files", name = "extractMetadata", paramType = "form", dataType = "boolean", required = false), + @ApiImplicitParam(value = "Metadata for this file", name = "metadata", paramType = "form", + dataType = "string"), + @ApiImplicitParam(value = "Enable metadata extraction from the content, for example for msg files", + name = "extractMetadata", paramType = "form", dataType = "boolean"), }) - - public void uploadNode(final WebScriptRequest multiPart, final WebScriptResponse response) throws IOException { + // TODO @Zlatin MVC Pojo + public ResponseEntity uploadNode( + @RequestPart(required = false) String type, + @RequestPart(required = false) String parent, + @RequestPart(required = false) Boolean extractMetadata, + @RequestPart(required = false) MetadataChanges metadata, + @RequestPart final MultipartFile file) { RetryingTransactionHelper transactionHelper = serviceRegistry.getRetryingTransactionHelper(); // Note the difference between: // * metadata = The metadata the user annotates the file with. // * extractMetadata = Whether the users wants metadata automatically extracted from the file. - // Both setting metadata and extracting metadata are optional. They can happen (or not) independently from each other. - String type = ContentModel.TYPE_CONTENT.toString(); - String parent = null; - FormData.FormField file = null; - Boolean extractMetadata = false; - MetadataChanges metadata = null; - - FormData formData = (FormData) multiPart.parseContent(); - for (FormData.FormField field : formData.getFields()) { - if (field.getName().equals("parent")) { - parent = field.getValue(); - } else if (field.getName().equals("type")) { - type = field.getValue(); - } else if (field.getName().equals("file") && field.getIsFile()) { - file = field; - } else if (field.getName().equals("metadata")) { - ObjectMapper mapper = new ObjectMapper(); - metadata = mapper.readValue(field.getValue(), MetadataChanges.class); - } else if (field.getName().equals("extractMetadata")) { - extractMetadata = Boolean.parseBoolean(field.getValue()); - } - } + // Both setting metadata and extracting metadata are optional. + // They can happen (or not) independently from each other. + type = type == null ? ContentModel.TYPE_CONTENT.toString() : type; + extractMetadata = extractMetadata != null && extractMetadata; if (file == null) { throw new IllegalArgumentException("Content must be supplied as a multipart 'file' field"); @@ -964,14 +863,13 @@ public void uploadNode(final WebScriptRequest multiPart, final WebScriptResponse } final String finalParent = parent; - final FormData.FormField finalFile = file; final String finalType = type; final MetadataChanges finalMetadata = metadata; final Boolean finalExtractMetadata = extractMetadata; - NodeRef resultRef = null; + NodeRef resultRef; try { resultRef = transactionHelper - .doInTransaction(() -> createNodeForUpload(finalParent, finalFile, finalType, finalMetadata, + .doInTransaction(() -> createNodeForUpload(finalParent, file, finalType, finalMetadata, finalExtractMetadata), false, true); } catch (org.alfresco.service.cmr.model.FileExistsException fileExistsException) { throw new FileExistsException( @@ -980,25 +878,25 @@ public void uploadNode(final WebScriptRequest multiPart, final WebScriptResponse fileExistsException.getName()); } NodeInfo nodeInfo = this - .nodeRefToNodeInfo((NodeRef) resultRef, fileFolderService, nodeService, permissionService); - writeJsonResponse(response, nodeInfo); + .nodeRefToNodeInfo(resultRef, fileFolderService, nodeService, permissionService); + return writeJsonResponse(nodeInfo); } public NodeRef createNodeForUpload(String finalParent, - FormData.FormField finalFile, + MultipartFile file, String finalType, MetadataChanges finalMetadata, - Boolean finalExtractMetadata) { + Boolean finalExtractMetadata) throws IOException { NodeRef newNode = nodeService - .createNode(new NodeRef(finalParent), finalFile.getFilename(), + .createNode(new NodeRef(finalParent), file.getOriginalFilename(), new QName(finalType)); - nodeService.setContent(newNode, finalFile.getInputStream(), finalFile.getFilename()); + nodeService.setContent(newNode, file.getInputStream(), file.getOriginalFilename()); if (finalMetadata != null) { nodeService.setMetadata(newNode, finalMetadata); } - if (finalExtractMetadata) { + if (Boolean.TRUE.equals(finalExtractMetadata)) { try { nodeService.extractMetadata(newNode); logger.debug("Metadata extracted"); @@ -1010,26 +908,27 @@ public NodeRef createNodeForUpload(String finalParent, } @ExceptionHandler(AccessDeniedException.class) - private void writeNotAuthorizedResponse(AccessDeniedException exception, WebScriptResponse response) - throws IOException { - logger.debug("Not Authorized: ", exception); - response.setStatus(403); - writeJsonResponse(response, "Not authorised to execute this operation"); + private ResponseEntity writeNotAuthorizedResponse(AccessDeniedException ex) { + logger.debug("Not Authorized", ex); + return ResponseEntity + .status(HttpStatus.SC_FORBIDDEN) + .body("Not authorised to execute this operation"); } @ExceptionHandler(FileExistsException.class) - private void writeFileExistsResponse(FileExistsException fileExistsException, WebScriptResponse response) - throws IOException { + private ResponseEntity writeFileExistsResponse(FileExistsException fileExistsException) { String message = fileExistsException.toString(); - logger.debug(message); - response.setStatus(400); - writeJsonResponse(response, message); + logger.debug(message, fileExistsException); + return ResponseEntity + .status(HttpStatus.SC_BAD_REQUEST) + .body(message); } - private void writeNotFoundResponse(WebScriptResponse response, NodeRef requestedNode) throws IOException { + private ResponseEntity writeNotFoundResponse(NodeRef requestedNode) { String message = String.format("Node Not Found: %s", requestedNode); logger.debug(message); - response.setStatus(404); - writeJsonResponse(response, message); + return ResponseEntity + .status(HttpStatus.SC_NOT_FOUND) + .body(message); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java index a4727196..4bd34453 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java @@ -1,74 +1,70 @@ package eu.xenit.apix.rest.v1.people; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.people.IPeopleService; import eu.xenit.apix.people.Person; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; import java.util.NoSuchElementException; -import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; -/** - * Created by Jasperhilven on 24-Oct-16. - */ -@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", - description = "Retrieves person information", value = "People") -@Authentication(AuthenticationType.USER) -@Component("eu.xenit.apix.rest.v1.people.PeopleWebscript") +//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", +// description = "Retrieves person information", value = "People") +//@Authentication(AuthenticationType.USER) +@RestController("eu.xenit.apix.rest.v1.people.PeopleWebscript") public class PeopleWebscript1 extends ApixV1Webscript { - Logger logger = LoggerFactory.getLogger(eu.xenit.apix.rest.v1.people.PeopleWebscript1.class); - @Autowired - IPeopleService personService; + private static final Logger logger = LoggerFactory.getLogger(PeopleWebscript1.class); + private final IPeopleService personService; - @Uri(value = "/people/{space}/{store}/{guid}", method = HttpMethod.GET) - @ApiOperation(value = "Returns person information", notes = "") + public PeopleWebscript1(IPeopleService personService) { + this.personService = personService; + } + + @GetMapping(value = "/v1/people/{space}/{store}/{guid}") + @ApiOperation(value = "Returns person information") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Person.class)) - public void getPerson(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, WebScriptResponse webScriptResponse) throws IOException { - logger.debug("Asked person with guid: " + guid); + public ResponseEntity getPerson(@PathVariable final String space, + @PathVariable final String store, + @PathVariable final String guid) { + logger.debug("Asked person with guid: {}", guid); try { - Person p = personService.GetPerson(createNodeRef(space, store, guid)); - writeJsonResponse(webScriptResponse, p); + return writeJsonResponse( + personService.GetPerson( + createNodeRef(space, store, guid) + ) + ); } catch (NoSuchElementException noSuchElementException) { - webScriptResponse.setStatus(HttpStatus.SC_NOT_FOUND); - writeJsonResponse(webScriptResponse, noSuchElementException.getMessage()); + return ResponseEntity.status(org.springframework.http.HttpStatus.NOT_FOUND) + .body(noSuchElementException.getMessage()); } catch (IllegalArgumentException illegalArgumentException) { - webScriptResponse.setStatus(HttpStatus.SC_BAD_REQUEST); - writeJsonResponse(webScriptResponse, illegalArgumentException.getMessage()); + return ResponseEntity.status(org.springframework.http.HttpStatus.BAD_REQUEST) + .body(illegalArgumentException.getMessage()); } } - @Uri(value = "/people", method = HttpMethod.GET) + @GetMapping(value = "/v1/people") @ApiOperation(value = "Returns person information given a userName", notes = "") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Person.class)) - public void getPersonViaUserName(@RequestParam final String userName, WebScriptResponse webScriptResponse) - throws IOException { - logger.debug("Asked person with name: " + userName); + public ResponseEntity getPersonViaUserName(@RequestParam final String userName) { + logger.debug("Asked person with name: {}", userName); try{ - Person p = personService.GetPerson(userName); - writeJsonResponse(webScriptResponse, p); + return writeJsonResponse( + personService.GetPerson(userName) + ); } catch (NoSuchElementException noSuchElementException) { - webScriptResponse.setStatus(HttpStatus.SC_NOT_FOUND); - writeJsonResponse(webScriptResponse, noSuchElementException.getMessage()); + return ResponseEntity.status(org.springframework.http.HttpStatus.NOT_FOUND) + .body(noSuchElementException.getMessage()); } catch (IllegalArgumentException illegalArgumentException) { - webScriptResponse.setStatus(HttpStatus.SC_BAD_REQUEST); - writeJsonResponse(webScriptResponse, illegalArgumentException.getMessage()); + return ResponseEntity.status(org.springframework.http.HttpStatus.BAD_REQUEST) + .body(illegalArgumentException.getMessage()); } } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java index 0dd28859..c554ff90 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java @@ -1,60 +1,52 @@ package eu.xenit.apix.rest.v1.properties; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; +import eu.xenit.apix.data.QName; import eu.xenit.apix.dictionary.properties.IPropertyService; import eu.xenit.apix.properties.PropertyDefinition; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; /** * Created by Jasperhilven on 13-Jan-17. * * @deprecated Use DictionaryWebScript1 instead */ -@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", - description = "Retrieves Property information", value = "Properties") -@Authentication(AuthenticationType.USER) -@Component("eu.xenit.apix.rest.v1.property.PropertiesWebScript1") +//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", +// description = "Retrieves Property information", value = "Properties") +//@Authentication(AuthenticationType.USER) +@RestController("eu.xenit.apix.rest.v1.property.PropertiesWebScript1") public class PropertiesWebScript1 extends ApixV1Webscript { - Logger logger = LoggerFactory.getLogger(PropertiesWebScript1.class); - - @Autowired - IPropertyService propertyService; + private final IPropertyService propertyService; + public PropertiesWebScript1(IPropertyService propertyService) { + this.propertyService = propertyService; + } - @Uri(value = "/properties/{qname}", method = HttpMethod.GET) + @GetMapping(value = "/v1/properties/{qname}") @ApiOperation(value = "Return the definition of a property", notes = "") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = PropertyDefinition.class)) //Use qname with slash to avoid //https://stackoverflow.com/questions/13482020/encoded-slash-2f-with-spring-requestmapping-path-param-gives-http-400 - public void getPropertyDefinition(@UriVariable final String qname, - @RequestParam(required = false) String qnameWithSlash, WebScriptResponse webScriptResponse) - throws IOException { - String qnameUsed = qnameWithSlash != null ? qnameWithSlash : qname; - String decoded = java.net.URLDecoder.decode(qnameUsed, "UTF-8"); - logger.debug("Asked versionhistory for node with guid: " + decoded); - eu.xenit.apix.data.QName apixQName = new eu.xenit.apix.data.QName(qnameUsed); + public ResponseEntity getPropertyDefinition(@PathVariable final QName qname, + @RequestParam(required = false) QName qnameWithSlash) { +// String qnameUsed = qnameWithSlash != null ? qnameWithSlash : qname; +// String decoded = java.net.URLDecoder.decode(qnameUsed, "UTF-8"); +// logger.debug("Asked versionhistory for node with guid: {}", decoded); +// eu.xenit.apix.data.QName apixQName = new eu.xenit.apix.data.QName(qnameUsed); + // TODO @Zlatin FIXME Alfresco MVC some crappy URL shenanigans ? Unit-tested? + QName apixQName = qnameWithSlash != null ? qnameWithSlash : qname; PropertyDefinition propDef = propertyService.GetPropertyDefinition(apixQName); if (propDef == null) { - webScriptResponse.setStatus(HttpStatus.NOT_FOUND.value()); + return ResponseEntity.notFound().build(); } - writeJsonResponse(webScriptResponse, propDef); + return writeJsonResponse(propDef); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java index 7133be7d..ce01c28d 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java @@ -1,70 +1,64 @@ package eu.xenit.apix.rest.v1.search; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import eu.xenit.apix.search.ISearchService; import eu.xenit.apix.search.SearchQuery; import eu.xenit.apix.search.SearchQueryResult; -import eu.xenit.apix.search.json.SearchNodeJsonParser; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; -import java.io.InputStream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; -/** - * Created by stan on 5/2/16. - */ -@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", - description = "Perform search queries", value = "Search") -@Authentication(AuthenticationType.USER) -@Qualifier("eu.xenit.apix.rest.v1.search.SearchWebScriptV1") -@Component("eu.xenit.apix.rest.v1.search.SearchWebScriptV1") +//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", +// description = "Perform search queries", value = "Search") +//@Authentication(AuthenticationType.USER) +@RestController("eu.xenit.apix.rest.v1.search.SearchWebScriptV1") public class SearchWebScript1 extends ApixV1Webscript { - Logger logger = LoggerFactory.getLogger(SearchWebScript1.class); - @Autowired - private ISearchService service; + private final ISearchService service; - @Uri(value = "/search", method = HttpMethod.POST) + public SearchWebScript1(ISearchService service) { + this.service = service; + } + + @PostMapping(value = "/v1/search") @ApiOperation(value = "Performs a search for nodes", notes ="# Request components\n" + "\n" + "## query\n" + "Object containing subcomponents that build the requested query.\n" - + "Info about the Search query syntax can be found here: https://docs.xenit.eu/alfred-api/stable-user/rest-api\n" + + "Info about the Search query syntax can be found here: " + + "https://docs.xenit.eu/alfred-api/stable-user/rest-api\n" + "### special search terms:\n" + "- type: searches for nodes of that type (for example: \"type\" : \"cm:content\")\n" + "- aspect: searches for nodes with that aspect (for example: \"aspect\" : \"cm:titled\")\n" - + "- noderef: searches the node with that noderef (for example: \"noderef\" : \"workspace://SpacesStore/f0d15919-3841-4170-807f-b81d2ebdeb80\")\n" - + "- parent: searches the nodes with that parent (for example: \"parent\" : \"workspace://SpacesStore/f0d15919-3841-4170-807f-b81d2ebdeb80\")\n" + + "- noderef: searches the node with that noderef (for example: \"noderef\" :" + + " \"workspace://SpacesStore/f0d15919-3841-4170-807f-b81d2ebdeb80\")\n" + + "- parent: searches the nodes with that parent (for example: \"parent\" : " + + "\"workspace://SpacesStore/f0d15919-3841-4170-807f-b81d2ebdeb80\")\n" + "- path: searches the nodes with that path (for example: \"path\" : \"/\")\n" - + "- category: searches the nodes with that category (for example: \"category\" : \"workspace://SpacesStore/f0d15919-3841-4170-807f-b81d2ebdeb80\")\n" + + "- category: searches the nodes with that category (for example: \"category\" : " + + "\"workspace://SpacesStore/f0d15919-3841-4170-807f-b81d2ebdeb80\")\n" + "- text: searches the nodes with content containing that text (for example: \"text\" : \"this text\")\n" - + "- all: searches the nodes with content, cm:name, cm:creator, cm:modifier or cm:author containing the value (for example: \"all\" : \"search term\")\n" - + "- isunset: searches the nodes with where the value of the property is not set (for example: \"isunset\" : \"cm:author\")\n" - + "- isnull: searches the nodes with where the value of the property is null (for example: \"isnull\" : \"cm:author\")\n" - + "- isnotnull: searches the nodes with where the value of the property is not null (for example: \"isnotnull\" : \"cm:author\")\n" + + "- all: searches the nodes with content, cm:name, cm:creator, cm:modifier or cm:author containing " + + "the value (for example: \"all\" : \"search term\")\n" + + "- isunset: searches the nodes with where the value of the property is not set (for example: " + + "\"isunset\" : \"cm:author\")\n" + + "- isnull: searches the nodes with where the value of the property is null (for example: \"isnull\" :" + + " \"cm:author\")\n" + + "- isnotnull: searches the nodes with where the value of the property is not null (for example: " + + "\"isnotnull\" : \"cm:author\")\n" + "- exists: searches the nodes that have the property (for example: \"exists\" : \"cm:author\")\n" + "\n" + "## paging\n" + "`Optional`\n" + "\n" - + "Options to skip over results starting from the top of the result and to limit the total number of results.\n" + + "Options to skip over results starting from the top of the result and " + + "to limit the total number of results.\n" + "\n" + "## facets\n" + "`Optional`\n" @@ -99,8 +93,11 @@ public class SearchWebScript1 extends ApixV1Webscript { + "`Optional`\n" + "\n" + "Options to change the highlight configuration.\n" - + "Minimal requirement is the `fields` array, which takes object containing at least the `field` property. Each list element specifies a property on which higlighting needs to be applied. When no fields are specified, the call defaults to `cm:content` as field.\n" - + "Full documentation can be found on the alfresco [documentation](https://docs.alfresco.com/5.2/concepts/search-api-highlight.html) page.\n" + + "Minimal requirement is the `fields` array, which takes object containing at least the `field` property. " + + "Each list element specifies a property on which higlighting needs to be applied. " + + "When no fields are specified, the call defaults to `cm:content` as field.\n" + + "Full documentation can be found on the alfresco " + + "[documentation](https://docs.alfresco.com/5.2/concepts/search-api-highlight.html) page.\n" + "\n" + "# Examples\n" + "\n" @@ -118,7 +115,8 @@ public class SearchWebScript1 extends ApixV1Webscript { + "}\n" + "```\n" + "\n" - + "Search for all nodes with the term 'budget' in the `cm:content` property (fulltext), and show two highlighted hits with delimiter \\\\:\n" + + "Search for all nodes with the term 'budget' in the `cm:content` property (fulltext), and show two " + + "highlighted hits with delimiter \\\\:\n" + "```json\n" + "{\n" + " \"query\": {\n" @@ -141,16 +139,11 @@ public class SearchWebScript1 extends ApixV1Webscript { @ApiResponse(code = 400, message = "Failure")}) @ApiImplicitParams({ @ApiImplicitParam(dataType = "eu.xenit.apix.search.SearchQuery", paramType = "body", name = "body")}) - public void execute(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) throws IOException { - ObjectMapper m = new SearchNodeJsonParser().getObjectMapper(); - InputStream stream = webScriptRequest.getContent().getInputStream(); - SearchQueryResult result = null; + public ResponseEntity execute(@RequestBody final SearchQuery query) { try { - result = service.query(m.readValue(stream, SearchQuery.class)); - writeJsonResponse(webScriptResponse, result); + return writeJsonResponse(service.query(query)); } catch (IllegalArgumentException illegalArgumentException) { - webScriptResponse.setStatus(400); - webScriptResponse.getWriter().write(illegalArgumentException.getMessage()); + return ResponseEntity.status(400).body(illegalArgumentException.getMessage()); } } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java index dda51332..e9215a11 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java @@ -1,56 +1,54 @@ package eu.xenit.apix.rest.v1.sites; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Transaction; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.filefolder.IFileFolderService; import eu.xenit.apix.node.INodeService; import eu.xenit.apix.permissions.IPermissionService; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import eu.xenit.apix.rest.v1.nodes.NodeInfo; import eu.xenit.apix.sites.ISite; import eu.xenit.apix.sites.ISiteService; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.security.AuthenticationService; -import org.json.JSONException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; -@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", - description = "Access operations on sites", value = "Sites") -@Transaction(readOnly = false) -@Component("eu.xenit.apix.rest.v1.SitesWebscript") +//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", +// description = "Access operations on sites", value = "Sites") +//@Transaction(readOnly = false) +@RestController("eu.xenit.apix.rest.v1.SitesWebscript") public class SitesWebscript1 extends ApixV1Webscript { - private final static Logger logger = LoggerFactory.getLogger(SitesWebscript1.class); + private static final Logger logger = LoggerFactory.getLogger(SitesWebscript1.class); - @Autowired - INodeService nodeService; + private final INodeService nodeService; - @Autowired - IPermissionService permissionService; + private final IPermissionService permissionService; - @Autowired - IFileFolderService fileFolderService; + private final IFileFolderService fileFolderService; - @Autowired - ISiteService siteService; + private final ISiteService siteService; - @Autowired - ServiceRegistry serviceRegistry; + private final ServiceRegistry serviceRegistry; + + public SitesWebscript1(INodeService nodeService, IPermissionService permissionService, + IFileFolderService fileFolderService, ISiteService siteService, + ServiceRegistry serviceRegistry) { + this.nodeService = nodeService; + this.permissionService = permissionService; + this.fileFolderService = fileFolderService; + this.siteService = siteService; + this.serviceRegistry = serviceRegistry; + } @ApiOperation(value = "Retrieves information about the available sites of the current user", notes = "Returns a list of sites. For each site the node reference, short name, title, description,\n" @@ -65,24 +63,23 @@ public class SitesWebscript1 extends ApixV1Webscript { + "Set 'retrieveParentAssocs' to true to return the parent associations of the sites.\n" + "Set 'retrieveTargetAssocs' to true to return the target peer associations of the sites.\n" + "Set 'retrieveSourceAssocs' to true to return the source peer associations of the sites.\n") - @Uri(value = "/sites/mySites", method = HttpMethod.GET) + @GetMapping(value = "/v1/sites/mySites") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = SiteInfo[].class)) - public void getMySites(@RequestParam(required = false, defaultValue = "false") Boolean retrieveMetadata, - @RequestParam(required = false, defaultValue = "false") boolean retrievePath, - @RequestParam(required = false, defaultValue = "false") boolean retrievePermissions, - @RequestParam(required = false, defaultValue = "false") boolean retrieveChildAssocs, - @RequestParam(required = false, defaultValue = "false") boolean retrieveParentAssocs, - @RequestParam(required = false, defaultValue = "false") boolean retrieveTargetAssocs, - @RequestParam(required = false, defaultValue = "false") boolean retrieveSourceAssocs, - WebScriptResponse response) - throws IOException { - logger.debug("retrieveMetadata: " + retrieveMetadata); - logger.debug("retrievePath: " + retrievePath); - logger.debug("retrievePermissions: " + retrievePermissions); - logger.debug("retrieveChildAssocs: " + retrieveChildAssocs); - logger.debug("retrieveParentAssocs: " + retrieveParentAssocs); - logger.debug("retrieveTargetAssocs: " + retrieveTargetAssocs); - logger.debug("retrieveSourceAssocs: " + retrieveSourceAssocs); + public ResponseEntity> getMySites( + @RequestParam(required = false, defaultValue = "false") Boolean retrieveMetadata, + @RequestParam(required = false, defaultValue = "false") boolean retrievePath, + @RequestParam(required = false, defaultValue = "false") boolean retrievePermissions, + @RequestParam(required = false, defaultValue = "false") boolean retrieveChildAssocs, + @RequestParam(required = false, defaultValue = "false") boolean retrieveParentAssocs, + @RequestParam(required = false, defaultValue = "false") boolean retrieveTargetAssocs, + @RequestParam(required = false, defaultValue = "false") boolean retrieveSourceAssocs) { + logger.debug("retrieveMetadata: {}", retrieveMetadata); + logger.debug("retrievePath: {}", retrievePath); + logger.debug("retrievePermissions: {}", retrievePermissions); + logger.debug("retrieveChildAssocs: {}", retrieveChildAssocs); + logger.debug("retrieveParentAssocs: {}", retrieveParentAssocs); + logger.debug("retrieveTargetAssocs: {}", retrieveTargetAssocs); + logger.debug("retrieveSourceAssocs: {}", retrieveSourceAssocs); AuthenticationService authService = serviceRegistry.getAuthenticationService(); List sites = siteService.getUserSites(authService.getCurrentUserName()); @@ -96,6 +93,6 @@ public void getMySites(@RequestParam(required = false, defaultValue = "false") B siteInfoList.add(siteInfo); } - writeJsonResponse(response, siteInfoList); + return writeJsonResponse(siteInfoList); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java index 068b8f7c..a6223c41 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java @@ -1,48 +1,41 @@ package eu.xenit.apix.rest.v1.temp; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import io.swagger.annotations.Api; import java.io.File; import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.core.env.Environment; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; -/** - * Created by Michiel Huygen on 03/05/2016. - */ -@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", - description = "Display logs") +//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", +// description = "Display logs") @Api(hidden = true) -@Component("eu.xenit.apix.rest.v1.temp.LogsWebscript") +@RestController("eu.xenit.apix.rest.v1.temp.LogsWebscript") public class LogsWebscript extends ApixV1Webscript { - @Uri(value = "/tmp/log", defaultFormat = "text") - @Authentication(AuthenticationType.ADMIN) - public void showLog(@RequestParam(defaultValue = "200") int lines, WebScriptResponse resp) throws IOException { - ArrayList output = new ArrayList(); + private final String logPath; - try (ReversedLinesFileReader reader = new ReversedLinesFileReader( - new File("/opt/alfresco/tomcat/logs/catalina.out"))) { + public LogsWebscript(Environment env) { + logPath = env.resolvePlaceholders("$CATALINA_HOME/logs/catalina.out"); + } + + @GetMapping(value = "/v1/tmp/log", produces = { MediaType.TEXT_PLAIN_VALUE }) +// @Authentication(AuthenticationType.ADMIN) + // TODO @Zlatin FIXME Alfresco MVC user permissions --> Admin! + public ResponseEntity showLog(@RequestParam(defaultValue = "200") int lines) throws IOException { + StringBuilder log = new StringBuilder(); + File logFile = new File(logPath); + try (ReversedLinesFileReader reader = new ReversedLinesFileReader(logFile)) { for (int i = 0; i < lines; i++) { - output.add(reader.readLine() + "\n"); + log.append(reader.readLine()) + .append("\n"); } } - - Writer writer = resp.getWriter(); - - for (int i = lines - 1; i >= 0; i--) { - writer.append(output.get(i)); - } - - + return ResponseEntity.ok(log.toString()); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java index d515a988..63a5ad7c 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java @@ -1,42 +1,39 @@ package eu.xenit.apix.rest.v1.temp; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.WIP.IWIPService; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; -/** - * Created by Michiel Huygen on 27/05/2016. - */ -@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", - description = "Work In Progress - UNSTABLE", value = "WIP") -@Component("eu.xenit.apix.rest.v1.temp.WIPWebscript") +//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", +// description = "Work In Progress - UNSTABLE", value = "WIP") +@RestController("eu.xenit.apix.rest.v1.temp.WIPWebscript") public class WIPWebscript extends ApixV1Webscript { - @Autowired - IWIPService WipService; + private final IWIPService wipService; + + public WIPWebscript(IWIPService wipService) { + this.wipService = wipService; + } @ApiOperation(value = "Downloads preview file for given node") - @Uri(value = "/nodes/{space}/{store}/{guid}/content/previews/pdf", method = HttpMethod.GET) + @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/content/previews/pdf") @ApiResponses(@ApiResponse(code = 200, message = "Success")) @ApiImplicitParams({@ApiImplicitParam(name = "file", paramType = "form", dataType = "file", required = true)}) - public void getPreviewPdf(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - final WebScriptRequest multiPart, WebScriptResponse response) throws IOException { + public ResponseEntity getPreviewPdf(@PathVariable String space, + @PathVariable String store, + @PathVariable String guid) { final NodeRef nodeRef = new NodeRef(space, store, guid); //TODO: from /searchapp/download + return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java index b7906360..ef2279bd 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java @@ -1,61 +1,53 @@ package eu.xenit.apix.rest.v1.translation; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import eu.xenit.apix.translation.ITranslationService; import eu.xenit.apix.translation.Translations; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; import java.util.Locale; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; /** * Created by Stan on 30-Mar-16. */ -@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", - description = "Retrieve translations", value = "Translations") -@Component("eu.xenit.apix.rest.v1.translation.TranslationsWebscript1") +//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", +// description = "Retrieve translations", value = "Translations") +@RestController("eu.xenit.apix.rest.v1.translation.TranslationsWebscript1") public class TranslationsWebscript1 extends ApixV1Webscript { - @Autowired - ITranslationService translationService; + private final ITranslationService translationService; + public TranslationsWebscript1(ITranslationService translationService) { + this.translationService = translationService; + } - @Uri(value = "/translations/{locale}/checksum", method = HttpMethod.GET) + @GetMapping(value = "/v1/translations/{locale}/checksum") @ApiOperation("Retrieve a checksum of all translations for given locale") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = TranslationChecksum.class)) - public void getChecksum(@UriVariable final String locale, WebScriptResponse response) throws IOException { + public ResponseEntity getChecksum(@PathVariable final String locale) { Locale language = Locale.forLanguageTag(locale); - Long checksum = translationService.getTranslationsCheckSum(language); - TranslationChecksum checksumObj = new TranslationChecksum(checksum); - - writeJsonResponse(response, checksumObj); + return writeJsonResponse(checksumObj); } - @Uri(value = "/translations/{locale}", method = HttpMethod.GET) + @GetMapping(value = "/v1/translations/{locale}") @ApiOperation("Get all available translations for given locale") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Translations.class)) - public void getTranslations(@UriVariable final String locale, WebScriptResponse response) throws IOException { + public ResponseEntity getTranslations(@PathVariable final String locale) { Locale language = Locale.forLanguageTag(locale); - Translations translations = translationService.getTranslations(language); - - writeJsonResponse(response, translations); + return writeJsonResponse(translations); } public static class TranslationChecksum { - public Long checksum; + private Long checksum; public TranslationChecksum(Long checksum) { this.checksum = checksum; @@ -69,6 +61,4 @@ public void setChecksum(Long checksum) { this.checksum = checksum; } } - - } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java index 5b10e93f..d235fbc3 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java @@ -1,16 +1,7 @@ package eu.xenit.apix.rest.v1.versionhistory; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.data.QName; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import eu.xenit.apix.versionhistory.IVersionHistoryService; import eu.xenit.apix.versionhistory.Version; import eu.xenit.apix.versionhistory.VersionHistory; @@ -19,94 +10,102 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; -import java.io.InputStream; import java.io.Serializable; import java.util.HashMap; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.surf.util.Content; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; /** * Created by stan on 5/2/16. */ -@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", - description = "Retrieves version history information", value = "VersionHistory") -@Authentication(AuthenticationType.USER) -@Component("eu.xenit.apix.rest.v1.versionhistory.VersionHistoryWebScript1") +//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", +// description = "Retrieves version history information", value = "VersionHistory") +//@Authentication(AuthenticationType.USER) +@RestController("eu.xenit.apix.rest.v1.versionhistory.VersionHistoryWebScript1") public class VersionHistoryWebScript1 extends ApixV1Webscript { - private final QName PROP_VERSION_LABEL = new QName("{http://www.alfresco.org/model/content/1.0}versionLabel"); - private final QName PROP_INITIAL_VERSION = new QName("{http://www.alfresco.org/model/content/1.0}initialVersion"); - private final QName PROP_AUTO_VERSION = new QName("{http://www.alfresco.org/model/content/1.0}autoVersion"); - private final QName PROP_AUTO_VERSION_PROPS = new QName( - "{http://www.alfresco.org/model/content/1.0}autoVersionOnUpdateProps"); - private final QName PROP_VERSION_TYPE = new QName("{http://www.alfresco.org/model/content/1.0}versionType"); + private static final Logger logger = LoggerFactory.getLogger(VersionHistoryWebScript1.class); - //@Autowired - //private ISearchService service; + private static final QName PROP_INITIAL_VERSION = + new QName("{http://www.alfresco.org/model/content/1.0}initialVersion"); + private static final QName PROP_AUTO_VERSION = + new QName("{http://www.alfresco.org/model/content/1.0}autoVersion"); + private static final QName PROP_AUTO_VERSION_PROPS = + new QName( + "{http://www.alfresco.org/model/content/1.0}autoVersionOnUpdateProps"); + private final IVersionHistoryService versionHistoryService; - Logger logger = LoggerFactory.getLogger(VersionHistoryWebScript1.class); - @Autowired - IVersionHistoryService versionHistoryService; + public VersionHistoryWebScript1(IVersionHistoryService versionHistoryService) { + this.versionHistoryService = versionHistoryService; + } - @Uri(value = "/versionhistory/{space}/{store}/{guid}/versions", method = HttpMethod.GET) - @ApiOperation(value = "Returns list of chronological version information for give node", notes = "") + @GetMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/versions") + @ApiOperation(value = "Returns list of chronological version information for give node") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = VersionHistory.class)) - public void getVersionHistory(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, WebScriptResponse webScriptResponse) throws IOException { - logger.debug("Asked versionhistory for node with guid: " + guid); - VersionHistory vH = versionHistoryService.GetVersionHistory(createNodeRef(space, store, guid)); - writeJsonResponse(webScriptResponse, vH); + public ResponseEntity getVersionHistory(@PathVariable final String space, + @PathVariable final String store, + @PathVariable final String guid) { + logger.debug("Asked versionhistory for node with guid: {}", guid); + return writeJsonResponse( + versionHistoryService.GetVersionHistory(createNodeRef(space, store, guid)) + ); } - @Uri(value = "/versionhistory/{space}/{store}/{guid}/root", method = HttpMethod.GET) + @GetMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/root") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Version.class)) @ApiOperation(value = "Returns the root (oldest) version") - public void getVersionHistoryRoot(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, WebScriptResponse webScriptResponse) throws IOException { - Version oldest = versionHistoryService.getRootVersion(createNodeRef(space, store, guid)); - writeJsonResponse(webScriptResponse, oldest); + public ResponseEntity getVersionHistoryRoot(@PathVariable final String space, + @PathVariable final String store, + @PathVariable final String guid) { + return writeJsonResponse( + versionHistoryService.getRootVersion(createNodeRef(space, store, guid)) + ); } - @Uri(value = "/versionhistory/{space}/{store}/{guid}/head", method = HttpMethod.GET) + @GetMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/head") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Version.class)) @ApiOperation(value = "Returns the head (newest) version") - public void getVersionHistoryHead(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, WebScriptResponse webScriptResponse) throws IOException { - Version newest = versionHistoryService.getHeadVersion(createNodeRef(space, store, guid)); - writeJsonResponse(webScriptResponse, newest); + public ResponseEntity getVersionHistoryHead(@PathVariable final String space, + @PathVariable final String store, + @PathVariable final String guid) { + return writeJsonResponse( + versionHistoryService.getHeadVersion(createNodeRef(space, store, guid)) + ); } - @Uri(value = "/versionhistory/{space}/{store}/{guid}", method = HttpMethod.DELETE) + @DeleteMapping(value = "/v1/versionhistory/{space}/{store}/{guid}") @ApiResponses(@ApiResponse(code = 200, message = "Success")) - //No method available to disable versioning. deleting will merely reset version history, starting a new history upon a new version change + //No method available to disable versioning. deleting will merely reset version history, + // starting a new history upon a new version change @ApiOperation(value = "Permanently emoves version history") - public void deleteVersionHistory(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, WebScriptResponse webScriptResponse) throws IOException { + public ResponseEntity deleteVersionHistory(@PathVariable final String space, + @PathVariable final String store, + @PathVariable final String guid) { versionHistoryService.deleteVersionHistory(createNodeRef(space, store, guid)); + return ResponseEntity.ok().build(); } - @Uri(value = "/versionhistory/{space}/{store}/{guid}", method = HttpMethod.PUT) + @PutMapping(value = "/v1/versionhistory/{space}/{store}/{guid}") @ApiResponses(@ApiResponse(code = 200, message = "Success")) @ApiImplicitParams({ - @ApiImplicitParam(dataType = "eu.xenit.apix.rest.v1.versionhistory.VersionOptions", paramType = "body", name = "body")}) + @ApiImplicitParam(dataType = "eu.xenit.apix.rest.v1.versionhistory.VersionOptions", + paramType = "body", name = "body")}) @ApiOperation(value = "Enables versioning for this node, creating an initial version") - public void setVersionHistory(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) - throws IOException { + public ResponseEntity setVersionHistory(@PathVariable final String space, + @PathVariable final String store, + @PathVariable final String guid, + @RequestBody(required = false) final VersionOptions versionOptions) { HashMap versionProperties = new HashMap<>(); - - Content requestContent = webScriptRequest.getContent(); - InputStream requestInputStream = requestContent.getInputStream(); - - try { - ObjectMapper objectMapper = new ObjectMapper(); - VersionOptions versionOptions = objectMapper.readValue(requestInputStream, VersionOptions.class); + if(versionOptions != null) { if (versionOptions.getAutoVersion() != null) { versionProperties.put(PROP_AUTO_VERSION, versionOptions.getAutoVersion()); } @@ -116,35 +115,30 @@ public void setVersionHistory(@UriVariable final String space, @UriVariable fina if (versionOptions.getInitialVersion() != null) { versionProperties.put(PROP_INITIAL_VERSION, versionOptions.getInitialVersion()); } - } catch (JsonMappingException ex) { - boolean isFirstChar = ex.getLocation().getLineNr() == 1 && ex.getLocation().getColumnNr() == 0; - boolean isAtStart = ex.getLocation().getByteOffset() == 0 || ex.getLocation().getCharOffset() == 0; - isAtStart |= ex.getLocation().getByteOffset() == -1 && isFirstChar; - if (!isAtStart) { - throw ex; - } - // Else, this is an exception because there is no body passed to the request } - versionHistoryService.ensureVersioningEnabled(createNodeRef(space, store, guid), versionProperties); + return ResponseEntity.ok().build(); } - @Uri(value = "/versionhistory/{space}/{store}/{guid}/versions/{label}/revert", method = HttpMethod.POST) + @PostMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/versions/{label}/revert") @ApiResponses(@ApiResponse(code = 200, message = "Success")) @ApiOperation(value = "(Shallow) Revert the node to version with given label") - public void revertVersionHistory(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, @UriVariable final String label, WebScriptResponse webScriptResponse) - throws IOException { + public ResponseEntity revertVersionHistory(@PathVariable final String space, + @PathVariable final String store, + @PathVariable final String guid, + @PathVariable final String label) { versionHistoryService.revert(createNodeRef(space, store, guid), label); + return ResponseEntity.ok().build(); } - @Uri(value = "/versionhistory/{space}/{store}/{guid}/versions/{label}", method = HttpMethod.DELETE) + @DeleteMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/versions/{label}") @ApiResponses(@ApiResponse(code = 200, message = "Success")) @ApiOperation(value = "Permanently remove version with given label") - public void deleteVersion(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, @UriVariable final String label, WebScriptResponse webScriptResponse) - throws IOException { + public ResponseEntity deleteVersion(@PathVariable final String space, + @PathVariable final String store, + @PathVariable final String guid, + @PathVariable final String label) { versionHistoryService.deleteVersion(createNodeRef(space, store, guid), label); + return ResponseEntity.ok().build(); } - } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java index d25bf3c4..51ac81a7 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java @@ -1,125 +1,106 @@ package eu.xenit.apix.rest.v1.workingcopies; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.data.NodeRef; -import eu.xenit.apix.filefolder.IFileFolderService; import eu.xenit.apix.node.INodeService; -import eu.xenit.apix.permissions.IPermissionService; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import eu.xenit.apix.rest.v1.RestV1Config; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; -import org.alfresco.service.ServiceRegistry; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; /** * Created by Michiel Huygen on 09/03/2016. */ -@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", - description = "Access operations on working copies", value = "Workingcopies") -@Component("eu.xenit.apix.rest.v1.WorkingcopiesWebscript1") +//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", +// description = "Access operations on working copies", value = "Workingcopies") +@RestController("eu.xenit.apix.rest.v1.WorkingcopiesWebscript1") public class WorkingcopiesWebscript1 extends ApixV1Webscript { - private final static Logger logger = LoggerFactory.getLogger(WorkingcopiesWebscript1.class); + private final INodeService nodeService; - @Autowired - INodeService nodeService; - - @Autowired - IPermissionService permissionService; - - @Autowired - IFileFolderService fileFolderService; - - @Autowired - ServiceRegistry serviceRegistry; + public WorkingcopiesWebscript1(INodeService nodeService) { + this.nodeService = nodeService; + } - @Uri(value = "/workingcopies", method = HttpMethod.POST) + @PostMapping(value = "/v1/workingcopies") @ApiOperation("Checks out a new working copy for given node") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = NoderefResult.class)) - public void createWorkingcopy(CheckoutBody checkoutBody, WebScriptResponse response) throws IOException { + public ResponseEntity createWorkingcopy(@RequestBody CheckoutBody checkoutBody) { final NodeRef originalRef = checkoutBody.getOriginal(); NodeRef destinationRef = checkoutBody.getDestinationFolder(); + if (!nodeService.exists(originalRef)) { + return respondDoesNotExist(originalRef); + } - if (nodeService.exists(originalRef)) { - // if a destinationRef was specified, it must exist, but nodeservice.checkout(..., null) works fine. - if (destinationRef == null || nodeService.exists(destinationRef)) { - NodeRef workingCopyRef = nodeService.checkout(originalRef, destinationRef); - writeJsonResponse(response, new NoderefResult(workingCopyRef)); - } else { - response.setStatus(404); - response.getWriter().write(String.format("Destination noderef %s does not exist", destinationRef)); - } - } else { - response.setStatus(404); - response.getWriter().write(String.format("Original noderef %s does not exist.", originalRef)); + // if a destinationRef was specified, it must exist, but nodeservice.checkout(..., null) works fine. + if (destinationRef == null || nodeService.exists(destinationRef)) { + NodeRef workingCopyRef = nodeService.checkout(originalRef, destinationRef); + return writeJsonResponse(new NoderefResult(workingCopyRef)); } + + return respondDoesNotExist(destinationRef); } - @ApiOperation(value = "Checks in given working copy and removes it", notes = "Returns the noderef of the original node") - @Uri(value = "/workingcopies/{space}/{store}/{guid}/checkin", method = HttpMethod.POST) + @ApiOperation(value = "Checks in given working copy and removes it", + notes = "Returns the noderef of the original node") + @PostMapping(value = "/v1/workingcopies/{space}/{store}/{guid}/checkin") @ApiResponses({ @ApiResponse(code = 200, message = "Success", response = NoderefResult.class), @ApiResponse(code = 404, message = "Not found") }) - public void checkinWorkingcopy(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, - final CheckinBody checkinBody, WebScriptResponse response) throws IOException { + public ResponseEntity checkinWorkingcopy(@PathVariable final String space, @PathVariable final String store, + @PathVariable final String guid, + @RequestBody final CheckinBody checkinBody) { final NodeRef nodeRef = createNodeRef(space, store, guid); if (nodeService.exists(nodeRef)) { NodeRef originalRef = nodeService.checkin(nodeRef, checkinBody.getComment(), checkinBody.getMajorVersion()); - writeJsonResponse(response, new NoderefResult(originalRef)); - } else { - response.setStatus(404); - response.getWriter().write(String.format("Noderef %s does not exist.", nodeRef)); + return writeJsonResponse(new NoderefResult(originalRef)); } + return respondDoesNotExist(nodeRef); } @ApiOperation(value = "Cancels and removes a working copy", notes = "Returns the noderef of the original node") - @Uri(value = "/workingcopies/{space}/{store}/{guid}", method = HttpMethod.DELETE) + @DeleteMapping(value = "/v1/workingcopies/{space}/{store}/{guid}") @ApiResponses({ @ApiResponse(code = 200, message = "Success", response = NoderefResult.class), @ApiResponse(code = 404, message = "Not found") }) - public void cancelWorkingcopy(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, - WebScriptResponse response) throws IOException { + public ResponseEntity cancelWorkingcopy(@PathVariable final String space, @PathVariable final String store, + @PathVariable final String guid) { final NodeRef workingCopyRef = createNodeRef(space, store, guid); if (nodeService.exists(workingCopyRef)) { NodeRef originalRef = nodeService.cancelCheckout(workingCopyRef); - writeJsonResponse(response, new NoderefResult(originalRef)); - } else { - response.setStatus(404); - response.getWriter().write(String.format("Noderef %s does not exist.", workingCopyRef)); + return writeJsonResponse(new NoderefResult(originalRef)); } + return respondDoesNotExist(workingCopyRef); } @ApiOperation("Returns the original node for given working copy") - @Uri(value = "/workingcopies/{space}/{store}/{guid}/original", method = HttpMethod.GET) + @GetMapping(value = "/v1/workingcopies/{space}/{store}/{guid}/original") @ApiResponses({ @ApiResponse(code = 200, message = "Success", response = NoderefResult.class), @ApiResponse(code = 404, message = "Not Found") }) - public void getWorkingCopySource(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, - WebScriptResponse response) throws IOException { + public ResponseEntity getWorkingCopySource(@PathVariable final String space, @PathVariable final String store, + @PathVariable final String guid) { NodeRef workingCopyRef = createNodeRef(space, store, guid); if (nodeService.exists(workingCopyRef)) { NodeRef originalRef = nodeService.getWorkingCopySource(workingCopyRef); - writeJsonResponse(response, new NoderefResult(originalRef)); - } else { - response.setStatus(404); - response.getWriter().write(String.format("Noderef %s does not exist.", workingCopyRef)); + return writeJsonResponse(new NoderefResult(originalRef)); } + + return respondDoesNotExist(workingCopyRef); } + private ResponseEntity respondDoesNotExist(NodeRef nodeRef) { + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(String.format(String.format("%s does not exist.", nodeRef))); + } } \ No newline at end of file diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/ApixV2Webscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/ApixV2Webscript.java index 73089f8f..029069f9 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/ApixV2Webscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/ApixV2Webscript.java @@ -2,7 +2,11 @@ import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.filefolder.IFileFolderService; -import eu.xenit.apix.node.*; +import eu.xenit.apix.node.ChildParentAssociation; +import eu.xenit.apix.node.INodeService; +import eu.xenit.apix.node.NodeAssociation; +import eu.xenit.apix.node.NodeAssociations; +import eu.xenit.apix.node.NodeMetadata; import eu.xenit.apix.permissions.IPermissionService; import eu.xenit.apix.permissions.PermissionValue; import eu.xenit.apix.rest.v1.ApixV1Webscript; @@ -19,11 +23,11 @@ */ public class ApixV2Webscript extends ApixV1Webscript { - private final static Logger logger = LoggerFactory.getLogger(ApixV2Webscript.class); + private static final Logger logger = LoggerFactory.getLogger(ApixV2Webscript.class); protected List nodeRefToNodeInfo(List nodeRefs, IFileFolderService fileFolderService, INodeService nodeService, IPermissionService permissionService) { - List nodeInfoList = new ArrayList(); + List nodeInfoList = new ArrayList<>(); for (NodeRef nodeRef : nodeRefs) { eu.xenit.apix.filefolder.NodePath path = fileFolderService.getPath(nodeRef); NodeMetadata nodeMetadata = nodeService.getMetadata(nodeRef); @@ -42,7 +46,7 @@ protected List nodeRefToNodeInfo(List nodeRefs, IFileFolderSe boolean retrievePermissions, boolean retrieveAssocs, boolean retrieveChildAssocs, boolean retrieveParentAssocs, boolean retrieveTargetAssocs, boolean retrieveSourceAssocs) { - List nodeInfoList = new ArrayList(); + List nodeInfoList = new ArrayList<>(); for (NodeRef nodeRef : nodeRefs) { if (!permissionService.hasPermission(nodeRef, IPermissionService.READ)) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java index e4a08f29..08f975e9 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java @@ -1,90 +1,86 @@ package eu.xenit.apix.rest.v2.groups; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.groups.Group; import eu.xenit.apix.people.IPeopleService; import eu.xenit.apix.people.Person; import eu.xenit.apix.rest.v2.ApixV2Webscript; -import eu.xenit.apix.rest.v2.RestV2Config; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; /** * Created by jasper on 14/03/17. */ -@WebScript(baseUri = RestV2Config.BaseUrl, families = RestV2Config.Family, defaultFormat = "json", - description = "Retrieves group information and links users/groups to parent groups", value = "Groups") -@Authentication(AuthenticationType.USER) -@Component("eu.xenit.apix.rest.v2.groups.GroupsWebscript") +//@WebScript(baseUri = RestV2Config.BaseUrl, families = RestV2Config.Family, defaultFormat = "json", +// description = "Retrieves group information and links users/groups to parent groups", value = "Groups") +//@Authentication(AuthenticationType.USER) +@RestController("eu.xenit.apix.rest.v2.groups.GroupsWebscript") public class GroupsWebscript extends ApixV2Webscript { Logger logger = LoggerFactory.getLogger(GroupsWebscript.class); - @Autowired - IPeopleService personService; + private final IPeopleService personService; - @Uri(value = "/groups", method = HttpMethod.GET) - @ApiOperation(value = "Returns a list containing all groups", notes = "") + public GroupsWebscript(IPeopleService personService) { + this.personService = personService; + } + + @GetMapping(value = "/v2/groups") + @ApiOperation(value = "Returns a list containing all groups") @ApiResponses(@ApiResponse(code = HttpStatus.SC_OK, message = "Success", response = Group[].class)) - public void GetAllGroups(WebScriptResponse webScriptResponse) throws IOException { - writeJsonResponse(webScriptResponse, personService.GetGroups()); + public ResponseEntity> GetAllGroups() { + return writeJsonResponse(personService.GetGroups()); } - @Uri(value = "/groups/{name}/people", method = HttpMethod.GET) - @ApiOperation(value = "Returns the persons within a specific group", notes = "") + @GetMapping(value = "/v2/groups/{name}/people") + @ApiOperation(value = "Returns the persons within a specific group") @ApiResponses(@ApiResponse(code = HttpStatus.SC_OK, message = "Success", response = Person[].class)) - public void GetPeopleOfGroup(@UriVariable final String name, @RequestParam(required = false) Boolean immediate, - WebScriptResponse webScriptResponse) throws IOException { + public ResponseEntity GetPeopleOfGroup(@PathVariable final String name, + @RequestParam(required = false) Boolean immediate) { if (immediate == null) { immediate = false; } List people = personService.GetUsersOfGroup(name, immediate); if (people == null) { - giveNoGroup404(webScriptResponse, name); - return; + return giveNoGroup404(name); } - writeJsonResponse(webScriptResponse, people); + return ResponseEntity.ok(people); } - @Uri(value = "/groups/{name}/groups", method = HttpMethod.GET) - @ApiOperation(value = "Returns the groups within a specific group", notes = "") + @GetMapping(value = "/v2/groups/{name}/groups") + @ApiOperation(value = "Returns the groups within a specific group") @ApiResponses(@ApiResponse(code = HttpStatus.SC_OK, message = "Success", response = Group[].class)) - public void GetGroupsOfGroup(@UriVariable final String name, @RequestParam(required = false) Boolean immediate, - WebScriptResponse webScriptResponse) throws IOException { + public ResponseEntity GetGroupsOfGroup(@PathVariable final String name, + @RequestParam(required = false) Boolean immediate) { if (immediate == null) { immediate = false; } List groups = personService.GetSubgroupsInGroup(name, immediate); if (groups == null) { - giveNoGroup404(webScriptResponse, name); - return; + return giveNoGroup404(name); } - writeJsonResponse(webScriptResponse, groups); + return writeJsonResponse(groups); } - @Uri(value = "/groups/{name}/people", method = HttpMethod.PUT) - @ApiOperation(value = "Sets the complete list of people as direct members of this group", notes = "") + @PutMapping(value = "/v2/groups/{name}/people") + @ApiOperation(value = "Sets the complete list of people as direct members of this group") @ApiResponses(@ApiResponse(code = HttpStatus.SC_OK, message = "Success", response = Group[].class)) - public void SetPeopleInGroup(@UriVariable final String name, SetUsersInGroupOptions options, - WebScriptResponse webScriptResponse) throws IOException { + public ResponseEntity SetPeopleInGroup(@PathVariable final String name, + @RequestBody SetUsersInGroupOptions options) { // We want to replace all of the users in group {name} by a new list of users // We're going to avoid unlinking and re-linking the same user, because iterating over the list to check for // duplicates is going to be cheaper than unnecessarily invoking all of Alfresco's internal safety checking @@ -93,8 +89,7 @@ public void SetPeopleInGroup(@UriVariable final String name, SetUsersInGroupOpti logger.debug("Setting new list of users for {}", name); // error handling, if {name} isn't a group if (linkedUsers == null) { - giveNoGroup404(webScriptResponse, name); - return; + return giveNoGroup404(name); } List oldUsers = new ArrayList<>(); @@ -104,14 +99,15 @@ public void SetPeopleInGroup(@UriVariable final String name, SetUsersInGroupOpti List newUsers = Arrays.asList(options.getUsers()); replaceAuthorities(name, oldUsers, newUsers); + return ResponseEntity.ok().build(); } - @Uri(value = "/groups/{name}/groups", method = HttpMethod.PUT) - @ApiOperation(value = "Sets the complete list of direct subgroups for this group", notes = "") + @PutMapping(value = "/v2/groups/{name}/groups") + @ApiOperation(value = "Sets the complete list of direct subgroups for this group") @ApiResponses(@ApiResponse(code = HttpStatus.SC_OK, message = "Success", response = Group[].class)) - public void SetGroupsOfGroup(@UriVariable final String name, SetSubgroupOptions options, - WebScriptResponse webScriptResponse) throws IOException { + public ResponseEntity SetGroupsOfGroup(@PathVariable final String name, + @RequestBody SetSubgroupOptions options) { // We want to replace all of the subgroups of {name} by a new list of subgroups // We're going to avoid unlinking and re-linking the same group, because iterating over the list to check for // duplicates is going to be cheaper than unnecessarily invoking all of Alfresco's internal safety checking @@ -120,8 +116,7 @@ public void SetGroupsOfGroup(@UriVariable final String name, SetSubgroupOptions logger.debug("Setting new list of subgroups for {}", name); // error handling, if {name} isn't a group if (linkedGroups == null) { - giveNoGroup404(webScriptResponse, name); - return; + return giveNoGroup404(name); } List oldGroups = new ArrayList<>(); @@ -131,11 +126,12 @@ public void SetGroupsOfGroup(@UriVariable final String name, SetSubgroupOptions List newGroups = Arrays.asList(options.getSubgroups()); replaceAuthorities(name, oldGroups, newGroups); + return ResponseEntity.ok().build(); } - private void giveNoGroup404(WebScriptResponse response, String name) throws IOException { - response.setStatus(HttpStatus.SC_NOT_FOUND); // 404 - response.getWriter().write("Group " + name + " does not exist"); + private ResponseEntity giveNoGroup404(String name) { + return ResponseEntity.status(HttpStatus.SC_NOT_FOUND) + .body("Group " + name + " does not exist"); } private void replaceAuthorities(String parentGroup, List oldOnes, List newOnes) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java index bbfda9fa..b5e29366 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java @@ -1,10 +1,5 @@ package eu.xenit.apix.rest.v2.nodes; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Transaction; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.data.QName; import eu.xenit.apix.filefolder.IFileFolderService; @@ -15,18 +10,13 @@ import eu.xenit.apix.rest.v1.nodes.CreateNodeOptions; import eu.xenit.apix.rest.v1.nodes.NodeInfo; import eu.xenit.apix.rest.v2.ApixV2Webscript; -import eu.xenit.apix.rest.v2.RestV2Config; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; -import org.alfresco.model.ContentModel; -import org.alfresco.repo.transaction.RetryingTransactionHelper; +import java.util.concurrent.atomic.AtomicInteger; import org.alfresco.service.ServiceRegistry; import org.apache.http.HttpStatus; import org.json.JSONArray; @@ -34,44 +24,53 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; -@WebScript(baseUri = RestV2Config.BaseUrl, families = RestV2Config.Family, defaultFormat = "json", - description = "Access operations on nodes", value = "Nodes") -@Transaction( - readOnly = false -) -@Component("eu.xenit.apix.rest.v2.NodesWebscript") +//@WebScript(baseUri = RestV2Config.BaseUrl, families = RestV2Config.Family, defaultFormat = "json", +// description = "Access operations on nodes", value = "Nodes") +//@Transaction( +// readOnly = false +//) +@RestController("eu.xenit.apix.rest.v2.NodesWebscript") public class NodesWebscriptV2 extends ApixV2Webscript { - private final static Logger logger = LoggerFactory.getLogger(NodesWebscriptV2.class); + private static final Logger logger = LoggerFactory.getLogger(NodesWebscriptV2.class); - @Autowired - INodeService nodeService; + private final INodeService nodeService; - @Autowired - IPermissionService permissionService; + private final IPermissionService permissionService; - @Autowired - IFileFolderService fileFolderService; + private final IFileFolderService fileFolderService; - @Autowired - ServiceRegistry serviceRegistry; + private final ServiceRegistry serviceRegistry; - @ApiOperation("Returns combined information of a node.\nNote: versionstore does not support sourceAssocs. For version nodes, an empty list added to the result") - @Uri(value = "/nodes/{space}/{store}/{guid}", method = HttpMethod.GET) + public NodesWebscriptV2(INodeService nodeService, IPermissionService permissionService, + IFileFolderService fileFolderService, ServiceRegistry serviceRegistry) { + this.nodeService = nodeService; + this.permissionService = permissionService; + this.fileFolderService = fileFolderService; + this.serviceRegistry = serviceRegistry; + } + + @ApiOperation("Returns combined information of a node." + + "\nNote: versionstore does not support sourceAssocs. " + + "For version nodes, an empty list added to the result") + @GetMapping(value = "/v2/nodes/{space}/{store}/{guid}") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = NodeInfo.class)) - public void getAllInfo(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptResponse response) throws IOException { + public ResponseEntity getAllInfo(@PathVariable String space, + @PathVariable String store, + @PathVariable String guid) { NodeRef nodeRef = this.createNodeRef(space, store, guid); NodeInfo nodeInfo = this .nodeRefToNodeInfo(nodeRef, this.fileFolderService, this.nodeService, this.permissionService); - writeJsonResponse(response, nodeInfo); + return writeJsonResponse(nodeInfo); } @ApiOperation(value = "Returns combined information of multiple nodes", @@ -94,33 +93,37 @@ public void getAllInfo(@UriVariable String space, @UriVariable String store, @Ur "]}\n" + "```" + "\n" + - "'retrieveMetadata', 'retrievePath', 'retrievePermissions', 'retrieveAssocs', 'retrieveChildAssocs',\n" + "'retrieveMetadata', 'retrievePath', 'retrievePermissions', 'retrieveAssocs', " + + "'retrieveChildAssocs',\n" + "'retrieveParentAssocs', 'retrieveTargetAssocs' are optional parameters.\n" + "Set 'retrieveMetadata' to false to omit the aspects and properties from the result.\n" + "Set 'retrievePath' to false to omit the path from the result.\n" + "Set 'retrievePermissions' to false to omit the permissions from the result.\n" + - "Set 'retrieveAssocs' to false to omit the associations (parent associations, child associations, peer associations) from the result.\n" + "Set 'retrieveAssocs' to false to omit the associations (parent associations, child associations," + + " peer associations) from the result.\n" + "Set 'retrieveChildAssocs' to false to omit the child associations from the result.\n" + "Set 'retrieveParentAssocs' to false to omit the parent associations from the result.\n" + "Set 'retrieveTargetAssocs' to false to omit the peer target associations from the result.\n" + - "Set 'retrieveSourceAssocs' to false to omit the peer source associations from the result. Note: versionstore does not support sourceAssocs. For version nodes, an empty list added to the result\n") - @Uri(value = "/nodes/nodeInfo", method = HttpMethod.POST) + "Set 'retrieveSourceAssocs' to false to omit the peer source associations from the result. " + + "Note: versionstore does not support sourceAssocs. For version nodes, an empty list added to the " + + "result\n") + @PostMapping(value = "/v2/nodes/nodeInfo") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = NodeInfo[].class)) - public void getAllInfos(WebScriptRequest request, WebScriptResponse response) throws IOException, JSONException { + // TODO FIXME @Zlatin Alfresco MVC POJO MUCH? WTF. + public ResponseEntity getAllInfos(@RequestBody final String requestString) throws JSONException { logger.debug("entered getAllInfo method"); - String requestString = request.getContent().getContent(); - logger.debug("request content: " + requestString); - JSONObject jsonObject = new JSONObject(requestString); - if (jsonObject == null) { - response.setStatus(400); + if (requestString == null || requestString.isEmpty()) { String message = String .format("Malfromed body: request string could not be parsed to jsonObject: %s", requestString); logger.debug(message); - writeJsonResponse(response, message); + return ResponseEntity.status(org.springframework.http.HttpStatus.BAD_REQUEST) + .body(message); } - logger.debug("json: " + jsonObject.toString()); + logger.debug("request content: {}", requestString); + JSONObject jsonObject = new JSONObject(requestString); + logger.debug("json: {}", jsonObject); boolean retrieveMetadata = true; boolean retrievePath = true; @@ -160,24 +163,23 @@ public void getAllInfos(WebScriptRequest request, WebScriptResponse response) th JSONArray nodeRefsJsonArray = jsonObject.getJSONArray("noderefs"); if (nodeRefsJsonArray == null) { - response.setStatus(400); String message = String.format("Could not retrieve target noderefs from body: %s", jsonObject); - logger.debug(message); - writeJsonResponse(response, message); + return ResponseEntity.status(org.springframework.http.HttpStatus.BAD_REQUEST) + .body(message); } int nodeRefsJsonArrayLength = nodeRefsJsonArray.length(); - logger.debug("nodeRefsJsonArrayLength: " + nodeRefsJsonArrayLength); + logger.debug("nodeRefsJsonArrayLength: {}", nodeRefsJsonArrayLength); for (int i = 0; i < nodeRefsJsonArrayLength; i++) { String nodeRefString = (String) nodeRefsJsonArray.get(i); - logger.debug("nodeRefString: " + nodeRefString); + logger.debug("nodeRefString: {}", nodeRefString); NodeRef nodeRef = new NodeRef(nodeRefString); nodeRefs.add(nodeRef); } } catch (JSONException e) { logger.error("Error deserializing json body", e); - String message = String.format("Malformed json body {}", jsonObject); - response.setStatus(400); - writeJsonResponse(response, message); + String message = String.format("Malformed json body %s", jsonObject); + return ResponseEntity.status(org.springframework.http.HttpStatus.BAD_REQUEST) + .body(message); } logger.debug("done parsing request data"); @@ -197,82 +199,88 @@ public void getAllInfos(WebScriptRequest request, WebScriptResponse response) th retrieveSourceAssocs); logger.debug("end nodeRefToNodeInfo"); - logger.debug("start writeJsonResponse"); - writeJsonResponse(response, nodeInfoList); - logger.debug("end writeJsonResponse"); + logger.debug("writeJsonResponse"); + return writeJsonResponse(nodeInfoList); } @ApiOperation(value = "Retrieve current user's permissions for a node", notes = "Returns a key-value map of permissions keys to a value of 'DENY' or 'ALLOW'. " + "Possible keys are: Read, Write, Delete, CreateChildren, ReadPermissions, ChangePermissions, " + "or custom permissions") - @Uri(value = "/nodes/{space}/{store}/{guid}/permissions", method = HttpMethod.GET) - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = PermissionValue.class, responseContainer = "Map")) - public void getPermissions(@UriVariable String space, @UriVariable String store, @UriVariable String guid, - WebScriptResponse response) throws IOException { + @GetMapping(value = "/v2/nodes/{space}/{store}/{guid}/permissions") + @ApiResponses( + @ApiResponse(code = 200, message = "Success", response = PermissionValue.class, responseContainer = "Map")) + public ResponseEntity> getPermissions(@PathVariable String space, + @PathVariable String store, + @PathVariable String guid) { NodeRef nodeRef = this.createNodeRef(space, store, guid); - - Map permissions = this.permissionService.getPermissionsFast(nodeRef); - writeJsonResponse(response, permissions); + return writeJsonResponse( + this.permissionService.getPermissionsFast(nodeRef) + ); } @ApiOperation("Creates or copies a node") - @Uri(value = "/nodes", method = HttpMethod.POST) + @PostMapping(value = "/v2/nodes") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = NodeInfo.class)) - public void createNode(final CreateNodeOptions createNodeOptions, WebScriptResponse response) throws IOException { + public ResponseEntity createNode(@RequestBody final CreateNodeOptions createNodeOptions) { + final StringBuilder errorMessage = new StringBuilder(); + final AtomicInteger errorCode = new AtomicInteger(); Object resultObject = serviceRegistry.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Object execute() throws Throwable { - NodeRef parent = new NodeRef(createNodeOptions.parent); - - if (!nodeService.exists(parent)) { - response.setStatus(HttpStatus.SC_NOT_FOUND); - writeJsonResponse(response, "Parent does not exist"); - return null; - } + .doInTransaction(() -> { + NodeRef parent = new NodeRef(createNodeOptions.parent); - NodeRef nodeRef; - NodeRef copyFrom = null; - if (createNodeOptions.copyFrom == null) { - nodeRef = nodeService - .createNode(parent, createNodeOptions.name, - new QName(createNodeOptions.type)); - } else { - copyFrom = new NodeRef(createNodeOptions.copyFrom); - if (!nodeService.exists(copyFrom)) { - response.setStatus(HttpStatus.SC_NOT_FOUND); - writeJsonResponse(response, "CopyFrom does not exist"); - return null; - } - nodeRef = nodeService.copyNode(copyFrom, parent, true); - } + if (!nodeService.exists(parent)) { + errorCode.addAndGet(HttpStatus.SC_NOT_FOUND); + errorMessage.append("Parent does not exist"); + return null; + } - MetadataChanges metadataChanges; - QName type; - if (createNodeOptions.type != null) { - type = new QName(createNodeOptions.type); - } else if ( createNodeOptions.type == null && createNodeOptions.copyFrom != null ) { - type = nodeService.getMetadata(copyFrom).type; - } else { - response.setStatus(HttpStatus.SC_BAD_REQUEST); - writeJsonResponse(response, - "Please provide parameter \"type\" when creating a new node"); + NodeRef nodeRef; + NodeRef copyFrom = null; + if (createNodeOptions.copyFrom == null) { + nodeRef = nodeService + .createNode(parent, createNodeOptions.name, + new QName(createNodeOptions.type)); + } else { + copyFrom = new NodeRef(createNodeOptions.copyFrom); + if (!nodeService.exists(copyFrom)) { + errorCode.addAndGet(HttpStatus.SC_NOT_FOUND); + errorMessage.append("CopyFrom does not exist"); return null; } - metadataChanges = new MetadataChanges(type, null, null, - createNodeOptions.properties); - nodeService.setMetadata(nodeRef, metadataChanges); + nodeRef = nodeService.copyNode(copyFrom, parent, true); + } - return nodeRef; + MetadataChanges metadataChanges; + QName type; + if (createNodeOptions.type != null) { + type = new QName(createNodeOptions.type); + } else if ( createNodeOptions.type == null && createNodeOptions.copyFrom != null ) { + type = nodeService.getMetadata(copyFrom).type; + } else { + errorCode.addAndGet(HttpStatus.SC_BAD_REQUEST); + errorMessage.append( + "Please provide parameter \"type\" when creating a new node" + ); + return null; } + metadataChanges = new MetadataChanges(type, null, null, + createNodeOptions.properties); + nodeService.setMetadata(nodeRef, metadataChanges); + + return nodeRef; }, false, true); + if(resultObject == null) { + return ResponseEntity.status(errorCode.get()) + .body(errorMessage.toString()); + } + NodeRef resultRef = new NodeRef(resultObject.toString()); NodeInfo nodeInfo = this .nodeRefToNodeInfo(resultRef, this.fileFolderService, this.nodeService, this.permissionService); - writeJsonResponse(response, nodeInfo); + return writeJsonResponse(nodeInfo); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java index 8e0d4358..c5394740 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java @@ -1,102 +1,93 @@ package eu.xenit.apix.rest.v2.people; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.apix.people.IPeopleService; import eu.xenit.apix.people.Person; import eu.xenit.apix.rest.v2.ApixV2Webscript; -import eu.xenit.apix.rest.v2.RestV2Config; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; -import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.webscripts.WebScriptResponse; -import org.springframework.stereotype.Component; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; -/** - * Created by Jasperhilven - */ -@WebScript(baseUri = RestV2Config.BaseUrl, families = RestV2Config.Family, defaultFormat = "json", - description = "Retrieves person information", value = "People") -@Authentication(AuthenticationType.USER) -@Component("eu.xenit.apix.rest.v2.people.PeopleWebscript") +//@WebScript(baseUri = RestV2Config.BaseUrl, families = RestV2Config.Family, defaultFormat = "json", +// description = "Retrieves person information", value = "People") +//@Authentication(AuthenticationType.USER) +@RestController("eu.xenit.apix.rest.v2.people.PeopleWebscript") public class PeopleWebscript extends ApixV2Webscript { - Logger logger = LoggerFactory.getLogger(PeopleWebscript.class); - @Autowired - IPeopleService personService; + private static final Logger logger = LoggerFactory.getLogger(PeopleWebscript.class); + private final IPeopleService personService; - @Uri(value = "/people/id/{space}/{store}/{guid}", method = HttpMethod.GET) - @ApiOperation(value = "Returns person information", notes = "") + public PeopleWebscript(IPeopleService personService) { + this.personService = personService; + } + + @GetMapping(value = "/v2/people/id/{space}/{store}/{guid}") + @ApiOperation(value = "Returns person information") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Person.class)) - public void getPerson(@UriVariable final String space, @UriVariable final String store, - @UriVariable final String guid, WebScriptResponse webScriptResponse) throws IOException { - logger.debug("Asked person with guid: " + guid); + public ResponseEntity getPerson(@PathVariable final String space, + @PathVariable final String store, + @PathVariable final String guid) { + logger.debug("Asked person with guid: {}", guid); try { - Person p = personService.GetPerson(createNodeRef(space, store, guid)); - writeJsonResponse(webScriptResponse, p); + return writeJsonResponse( + personService.GetPerson(createNodeRef(space, store, guid)) + ); } catch (NoSuchElementException noSuchElementException) { - webScriptResponse.setStatus(HttpStatus.SC_NOT_FOUND); - writeJsonResponse(webScriptResponse, noSuchElementException); + return ResponseEntity.status(org.springframework.http.HttpStatus.NOT_FOUND) + .body(noSuchElementException.getMessage()); } catch (IllegalArgumentException illegalArgumentException) { - webScriptResponse.setStatus(HttpStatus.SC_BAD_REQUEST); - writeJsonResponse(webScriptResponse, illegalArgumentException); + return ResponseEntity.status(org.springframework.http.HttpStatus.BAD_REQUEST) + .body(illegalArgumentException.getMessage()); } } - @Uri(value = "/people", method = HttpMethod.GET) - @ApiOperation(value = "Returns all people", notes = "") + @GetMapping(value = "/v2/people") + @ApiOperation(value = "Returns all people") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Person[].class)) - public void getAllPeople(WebScriptResponse webScriptResponse) throws IOException { - List people = personService.GetPeople(); - writeJsonResponse(webScriptResponse, people); - return; + public ResponseEntity> getAllPeople() { + return writeJsonResponse(personService.GetPeople()); } - @Uri(value = "/people/-me-", method = HttpMethod.GET) - @ApiOperation(value = "Returns current user information", notes = "") + @GetMapping(value = "/v2/people/-me-") + @ApiOperation(value = "Returns current user information") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Person.class)) - public void getPersonCurrentUser(WebScriptResponse webScriptResponse) throws IOException { - getPersonWithName("-me-", webScriptResponse); + public ResponseEntity getPersonCurrentUser() { + return getPersonWithName("-me-"); } - @Uri(value = "/people/{name}", method = HttpMethod.GET) - @ApiOperation(value = "Returns person information", notes = "") + @GetMapping(value = "/v2/people/{name}") + @ApiOperation(value = "Returns person information") @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Person.class)) - public void getPersonWithName(@UriVariable final String name, WebScriptResponse webScriptResponse) - throws IOException { - logger.debug("Asked person with name: " + name); + public ResponseEntity getPersonWithName(@PathVariable final String name) { + logger.debug("Asked person with name: {}", name); try{ - Person p = personService.GetPerson(name); - writeJsonResponse(webScriptResponse, p); + return writeJsonResponse( + personService.GetPerson(name) + ); } catch (NoSuchElementException noSuchElementException) { - webScriptResponse.setStatus(HttpStatus.SC_NOT_FOUND); - writeJsonResponse(webScriptResponse, noSuchElementException.getMessage()); + return ResponseEntity.status(org.springframework.http.HttpStatus.NOT_FOUND) + .body(noSuchElementException.getMessage()); } catch (IllegalArgumentException illegalArgumentException) { - webScriptResponse.setStatus(HttpStatus.SC_BAD_REQUEST); - writeJsonResponse(webScriptResponse, illegalArgumentException.getMessage()); + return ResponseEntity.status(org.springframework.http.HttpStatus.BAD_REQUEST) + .body(illegalArgumentException.getMessage()); } } - @Uri(value = "/people/containergroups/{name}", method = HttpMethod.GET) - @ApiOperation(value = "Returns container groups of person", notes = "") + @GetMapping(value = "/v2/ people/containergroups/{name}") + @ApiOperation(value = "Returns container groups of person") @ApiResponses(value = @ApiResponse(code = 200, message = "Success", response = String[].class)) - public void getContainerGroupsOf(@UriVariable final String name, WebScriptResponse webScriptResponse) - throws IOException { - logger.debug("Asked containergroups for person with name: " + name); + public ResponseEntity> getContainerGroupsOf(@PathVariable final String name) { + logger.debug("Asked containergroups for person with name: {}", name); Set result = personService.GetContainerGroups(name); - writeJsonResponse(webScriptResponse, new ArrayList(result)); + return writeJsonResponse(new ArrayList<>(result)); } } diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.delete.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.delete.desc.xml new file mode 100644 index 00000000..767beea3 --- /dev/null +++ b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.delete.desc.xml @@ -0,0 +1,11 @@ + + Alfred API Delete + /apix/{path} + user + required + + + + true + + \ No newline at end of file diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.get.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.get.desc.xml new file mode 100644 index 00000000..a927e7d7 --- /dev/null +++ b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.get.desc.xml @@ -0,0 +1,11 @@ + + Alfred API Get + /apix/{path} + user + none + + + + true + + \ No newline at end of file diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.post.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.post.desc.xml new file mode 100644 index 00000000..71b5f35a --- /dev/null +++ b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.post.desc.xml @@ -0,0 +1,11 @@ + + Alfred API Post + /apix/{path} + user + required + + + + true + + \ No newline at end of file diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.put.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.put.desc.xml new file mode 100644 index 00000000..aa9bd4e8 --- /dev/null +++ b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.put.desc.xml @@ -0,0 +1,11 @@ + + Alfred API Put + /apix/{path} + user + required + + + + true + + \ No newline at end of file diff --git a/apix-rest-v1/src/main/resources/alfresco/module/alfred-api/module-context.xml b/apix-rest-v1/src/main/resources/alfresco/module/alfred-api/module-context.xml new file mode 100644 index 00000000..df7b823b --- /dev/null +++ b/apix-rest-v1/src/main/resources/alfresco/module/alfred-api/module-context.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/apix-rest-v1/src/main/resources/alfresco/module/alfred-api/module.properties b/apix-rest-v1/src/main/resources/alfresco/module/alfred-api/module.properties new file mode 100644 index 00000000..b61f87a8 --- /dev/null +++ b/apix-rest-v1/src/main/resources/alfresco/module/alfred-api/module.properties @@ -0,0 +1,52 @@ +# 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. + + + +# SDK Sample module + +# ==== Beginning of Alfresco required/optional properties ====== # +# NB: These properties are filtered at build time by Maven, single +# sourcing from POM properties +#module.id=${project.name} +module.id=alfred-api +#module.aliases=myModule-123, my-module +#module.title=${project.name} +module.title=Alfred API +#module.description=${project.description} +module.description=Alfred API: Java and ReST APIs +#module.version=${project.version} +module.version=4.0 + +# The following optional properties can be used to prevent the module from being added +# to inappropriate versions of the WAR file. +# module.repo.version.min=2.0 +# module.repo.version.max=2.1 + +# FIXME: This dependencies should come out of mvn dependencies on amp + +# The following describe dependencies on other modules +# Depends on net.sf.myproject.module.SupportModuleA version ${version} or later +# module.depends.net.sf.myproject.module.SupportModuleA=${version}-* +# Depends on net.sf.myproject.module.SupportModuleA version ${version} to 2.0 +# module.depends.net.sf.myproject.module.SupportModuleB=${version}-2.0 +# Depends on net.sf.myproject.module.SupportModuleC - any version +# module.depends.net.sf.myproject.module.SupportModuleB=* + + +# ==== End of Alfresco required/optional properties ======= # + + +# ==== Beginning of module required properties/optional ====== # \ No newline at end of file diff --git a/apix-rest-v1/src/main/resources/application.properties b/apix-rest-v1/src/main/resources/application.properties new file mode 100644 index 00000000..71ec92ff --- /dev/null +++ b/apix-rest-v1/src/main/resources/application.properties @@ -0,0 +1,2 @@ +management.endpoint.shutdown.enabled=true +management.endpoints.web.exposure.include=* \ No newline at end of file diff --git a/apix-rest-v1/src/main/resources/log4j.properties b/apix-rest-v1/src/main/resources/log4j.properties index 18cfaa3f..74996e6b 100644 --- a/apix-rest-v1/src/main/resources/log4j.properties +++ b/apix-rest-v1/src/main/resources/log4j.properties @@ -5,4 +5,5 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.threshold=TRACE #log4j.logger.org.springframework.osgi=DEBUG -#log4j.logger.org.springframework=DEBUG \ No newline at end of file +#log4j.logger.org.springframework=DEBUG +log4j.logger.org.springframework.web.servlet.mvc.support=DEBUG \ No newline at end of file diff --git a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/DocumentationWebscriptTest.java b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/DocumentationWebscriptTest.java index 61342317..cf075418 100644 --- a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/DocumentationWebscriptTest.java +++ b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/DocumentationWebscriptTest.java @@ -1,67 +1,67 @@ -package eu.xenit.apix.rest; - -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.fasterxml.jackson.core.JsonProcessingException; -import eu.xenit.apix.rest.v1.DocumentationWebscript; -import eu.xenit.apix.version.IVersionService; -import eu.xenit.apix.version.VersionDescription; -import eu.xenit.apix.web.IWebUtils; -import io.swagger.models.Path; -import io.swagger.models.Swagger; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.Property; -import io.swagger.util.Json; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.extensions.surf.util.URLEncoder; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; - - -public class DocumentationWebscriptTest { - - @Test - public void TestGenerate() throws JsonProcessingException { - String swagText = Json.mapper().writeValueAsString(generateSwagger()); - System.out.println(swagText); - Assert.assertTrue(0 < swagText.length()); - } - - @Test - public void TestPermissionsMap() { - Swagger swag = generateSwagger(); - Path path = swag.getPath("/v1/nodes/{space}/{store}/{guid}/permissions"); - Property schema = path.getGet().getResponses().get("200").getSchema(); - Assert.assertTrue("Nodes permissions get should return a map", schema instanceof MapProperty); - System.out.println(schema); - } - - private Swagger generateSwagger() { - IVersionService version = mock(IVersionService.class); - IWebUtils webUtils = mock(IWebUtils.class); - when(version.getVersionDescription()).thenReturn(new VersionDescription("1.0.unittest", "description")); - when(webUtils.getHost()).thenReturn("http"); - DocumentationWebscript web = new DocumentationWebscript(version, webUtils); - return web.generateSwagger(); - } - - @Test - public void testRedirectToSwaggerUi() { - WebScriptRequest request = mock(WebScriptRequest.class); - String serviceContextPath = "https://testdomain.com/alfresco/service"; - when(request.getServiceContextPath()).thenReturn(serviceContextPath); - when(request.getServicePath()).thenReturn(serviceContextPath.concat("/apix/v1/docs/ui")); - WebScriptResponse response = mock(WebScriptResponse.class); - DocumentationWebscript documentationWebscript = new DocumentationWebscript(mock(IVersionService.class), - mock(IWebUtils.class)); - documentationWebscript.redirectToSwaggerUi(request, response); - verify(response).setStatus(302); - verify(response).setHeader(eq("Location"), - eq("https://testdomain.com/alfresco/service/swagger/ui/?url=" + URLEncoder - .encode("https://testdomain.com/alfresco/service/apix/v1/docs/swagger.json"))); - } -} +//package eu.xenit.apix.rest; +// +//import static org.mockito.Mockito.eq; +//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.verify; +//import static org.mockito.Mockito.when; +// +//import com.fasterxml.jackson.core.JsonProcessingException; +//import eu.xenit.apix.rest.v1.DocumentationWebscript; +//import eu.xenit.apix.version.IVersionService; +//import eu.xenit.apix.version.VersionDescription; +//import eu.xenit.apix.web.IWebUtils; +//import io.swagger.models.Path; +//import io.swagger.models.Swagger; +//import io.swagger.models.properties.MapProperty; +//import io.swagger.models.properties.Property; +//import io.swagger.util.Json; +//import org.junit.Assert; +//import org.junit.Test; +//import org.springframework.extensions.surf.util.URLEncoder; +//import org.springframework.extensions.webscripts.WebScriptRequest; +//import org.springframework.extensions.webscripts.WebScriptResponse; +// +// +//public class DocumentationWebscriptTest { +// +// @Test +// public void TestGenerate() throws JsonProcessingException { +// String swagText = Json.mapper().writeValueAsString(generateSwagger()); +// System.out.println(swagText); +// Assert.assertTrue(0 < swagText.length()); +// } +// +// @Test +// public void TestPermissionsMap() { +// Swagger swag = generateSwagger(); +// Path path = swag.getPath("/v1/nodes/{space}/{store}/{guid}/permissions"); +// Property schema = path.getGet().getResponses().get("200").getSchema(); +// Assert.assertTrue("Nodes permissions get should return a map", schema instanceof MapProperty); +// System.out.println(schema); +// } +// +// private Swagger generateSwagger() { +// IVersionService version = mock(IVersionService.class); +// IWebUtils webUtils = mock(IWebUtils.class); +// when(version.getVersionDescription()).thenReturn(new VersionDescription("1.0.unittest", "description")); +// when(webUtils.getHost()).thenReturn("http"); +// DocumentationWebscript web = new DocumentationWebscript(version, webUtils); +// return web.generateSwagger(); +// } +// +// @Test +// public void testRedirectToSwaggerUi() { +// WebScriptRequest request = mock(WebScriptRequest.class); +// String serviceContextPath = "https://testdomain.com/alfresco/service"; +// when(request.getServiceContextPath()).thenReturn(serviceContextPath); +// when(request.getServicePath()).thenReturn(serviceContextPath.concat("/apix/v1/docs/ui")); +// WebScriptResponse response = mock(WebScriptResponse.class); +// DocumentationWebscript documentationWebscript = new DocumentationWebscript(mock(IVersionService.class), +// mock(IWebUtils.class)); +// documentationWebscript.redirectToSwaggerUi(request, response); +// verify(response).setStatus(302); +// verify(response).setHeader(eq("Location"), +// eq("https://testdomain.com/alfresco/service/swagger/ui/?url=" + URLEncoder +// .encode("https://testdomain.com/alfresco/service/apix/v1/docs/swagger.json"))); +// } +//} diff --git a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/NodesWebscript1Test.java b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/NodesWebscript1Test.java index c820485e..eec8cace 100644 --- a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/NodesWebscript1Test.java +++ b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/NodesWebscript1Test.java @@ -11,16 +11,18 @@ import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.node.INodeService; import eu.xenit.apix.rest.v1.nodes.NodesWebscript1; + +import java.io.IOException; import java.io.InputStream; import org.springframework.extensions.webscripts.servlet.FormData; import org.junit.Test; -import org.mockito.internal.util.reflection.FieldSetter; import org.springframework.extensions.webscripts.servlet.FormData.FormField; +import org.springframework.web.multipart.MultipartFile; public class NodesWebscript1Test { @Test - public void test_uploadNode_triggerMetadataExtract() throws NoSuchFieldException { + public void test_uploadNode_triggerMetadataExtract() throws IOException { //Setup mocks INodeService nodeServiceMock = mock(NodeService.class); when(nodeServiceMock.createNode(any(), any(), any())) @@ -28,11 +30,11 @@ public void test_uploadNode_triggerMetadataExtract() throws NoSuchFieldException doNothing().when(nodeServiceMock).setContent(any(), any(), any()); doNothing().when(nodeServiceMock).extractMetadata(any()); - NodesWebscript1 nodesWebscript = new NodesWebscript1(); - FieldSetter.setField(nodesWebscript, NodesWebscript1.class.getDeclaredField("nodeService"), nodeServiceMock); + NodesWebscript1 nodesWebscript = new NodesWebscript1(nodeServiceMock, + null, null, null, null); - FormField fileMock = mock(FormData.FormField.class); - when(fileMock.getFilename()).thenReturn("testFile"); + MultipartFile fileMock = mock(MultipartFile.class); + when(fileMock.getOriginalFilename()).thenReturn("testFile"); InputStream inputStreamMock = mock(InputStream.class); when(fileMock.getInputStream()).thenReturn(inputStreamMock); diff --git a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/TestDEWebscript1.java b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/TestDEWebscript1.java index 8b31a582..90f85fbd 100644 --- a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/TestDEWebscript1.java +++ b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/TestDEWebscript1.java @@ -1,25 +1,24 @@ package eu.xenit.apix.rest; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication; -import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; /** * Created by Michiel Huygen on 29/03/2016. */ -@WebScript(baseUri = "/base", families = "My Family", value = "TestDEWebscript") -@Authentication(AuthenticationType.GUEST) +@RestController +//@WebScript(baseUri = "/base", families = "My Family", value = "TestDEWebscript") +//@Authentication(AuthenticationType.GUEST) public class TestDEWebscript1 { - @Uri("/method") + @GetMapping("/method") public void testGet() { } - @Authentication(AuthenticationType.ADMIN) - @Uri(value = "/method/{param}", method = HttpMethod.POST) +// @Authentication(AuthenticationType.ADMIN) + @PostMapping(value = "/method/{param}") public void testPost() { } diff --git a/build.gradle b/build.gradle index 0c455429..05913c6c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,28 +1,28 @@ -def bundleClassPath(configuration) { - def list = ['.'] - configuration.each { - list += 'lib/' + it.name - } - return list.join(',') -} - -def includeResource(configuration) { - def list = [] - configuration.each { - //We have to replace the backslashes with forward slashes because on windows the path will just be unseparated. - //For example when you have path "C\:Users\Someone\.gradle\caches" it will become "C\:UsersSomeone.gradlecaches" - def normalizedPath = it.path.replace("\\", "/") - list += 'lib/' + it.name + "=" + normalizedPath - } - return list.join(',') -} - -def getVersionQualifier(String branch_name) { - if(branch_name.startsWith('release')) - return '' - //Osgi in 5x accepts - in qualifier, 6x does not. Suggest removing branch section from snapshot qualifiers all together. - return '.SNAPSHOT' -} +//def bundleClassPath(configuration) { +// def list = ['.'] +// configuration.each { +// list += 'lib/' + it.name +// } +// return list.join(',') +//} +// +//def includeResource(configuration) { +// def list = [] +// configuration.each { +// //We have to replace the backslashes with forward slashes because on windows the path will just be unseparated. +// //For example when you have path "C\:Users\Someone\.gradle\caches" it will become "C\:UsersSomeone.gradlecaches" +// def normalizedPath = it.path.replace("\\", "/") +// list += 'lib/' + it.name + "=" + normalizedPath +// } +// return list.join(',') +//} +// +//def getVersionQualifier(String branch_name) { +// if(branch_name.startsWith('release')) +// return '' +// //Osgi in 5x accepts - in qualifier, 6x does not. Suggest removing branch section from snapshot qualifiers all together. +// return '.SNAPSHOT' +//} buildscript { repositories { @@ -37,7 +37,7 @@ ext { versionWithoutQualifier = '4.0.0' jackson_version = '2.8.3' - swagger_version = "1.5.7" + swagger_version = "1.5.7" // 2.2.4 de_version = "3.0.0" http_core_version = "4.3.3" @@ -58,16 +58,18 @@ ext { alfresco_73_dm_version = "17.175" care4alfVersion = '2.3.0' + + mvc = "8.0.0" + alfrescoVersion = "7.2.0" } subprojects { apply plugin: 'java' - apply plugin: 'maven' group = 'eu.xenit.apix' - version = versionWithoutQualifier + getVersionQualifier(System.env.BRANCH_NAME ?: 'local') - sourceCompatibility = 1.8 - targetCompatibility = 1.8 + version = "4.0" // versionWithoutQualifier + getVersionQualifier(System.env.BRANCH_NAME ?: 'local') + sourceCompatibility = 11 + targetCompatibility = 11 repositories { mavenCentral() diff --git a/de-swagger-reader/build.gradle b/de-swagger-reader/build.gradle index 21d5f48b..0a2561ec 100644 --- a/de-swagger-reader/build.gradle +++ b/de-swagger-reader/build.gradle @@ -4,12 +4,12 @@ description = 'Xenit Dynamic-extensions Swagger Reader' apply plugin: 'osgi' dependencies { - compile group: 'commons-io', name: 'commons-io', version: '2.0.1' - compile(group: 'io.swagger', name: 'swagger-core', version: swagger_version) { + implementation group: 'commons-io', name: 'commons-io', version: '2.0.1' + implementation(group: 'io.swagger', name: 'swagger-core', version: swagger_version) { exclude group: 'org.slf4j', module: 'slf4j-api' } compileOnly group: 'org.slf4j', name: 'slf4j-api', version: '1.7.22' - compile group: 'io.swagger', name: 'swagger-annotations', version: swagger_version + implementation group: 'io.swagger', name: 'swagger-annotations', version: swagger_version compileOnly(group: 'eu.xenit.de', name: 'annotations', version: de_version) { transitive = false } diff --git a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/DESwaggerExtension.java b/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/DESwaggerExtension.java index 0972d366..6e77e5a6 100644 --- a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/DESwaggerExtension.java +++ b/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/DESwaggerExtension.java @@ -2,8 +2,6 @@ import com.fasterxml.jackson.databind.type.ArrayType; import com.fasterxml.jackson.databind.type.SimpleType; -import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; import eu.xenit.swagger.reader.ext.AbstractSwaggerExtension; import eu.xenit.swagger.reader.ext.SwaggerExtension; import io.swagger.models.parameters.Parameter; @@ -44,7 +42,6 @@ public List extractParameters(List annotations, Type type } for (Annotation ann : annotations) { - if (ann.annotationType().equals(RequestParam.class)) { RequestParam c = (RequestParam) ann; @@ -56,14 +53,6 @@ public List extractParameters(List annotations, Type type return Collections.singletonList((Parameter) parameter); } - if (ann.annotationType().equals(UriVariable.class)) { - UriVariable c = (UriVariable) ann; - PathParameter parameter = new PathParameter(); - parameter.setRequired(c.required()); - parameter.setName(c.value()); - parameter.setType("string"); - return Collections.singletonList((Parameter) parameter); - } } return Collections.emptyList(); diff --git a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/Reader.java b/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/Reader.java index 5191e4b0..86c6021a 100644 --- a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/Reader.java +++ b/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/Reader.java @@ -15,8 +15,6 @@ import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; import eu.xenit.swagger.reader.ext.SwaggerExtension; import eu.xenit.swagger.reader.ext.SwaggerExtensions; import eu.xenit.swagger.reader.utils.ReaderUtils; diff --git a/de-swagger-reader/src/test/java/io/swagger/sample/reader/DEWebscript.java b/de-swagger-reader/src/test/java/io/swagger/sample/reader/DEWebscript.java index 67f49250..630e7687 100644 --- a/de-swagger-reader/src/test/java/io/swagger/sample/reader/DEWebscript.java +++ b/de-swagger-reader/src/test/java/io/swagger/sample/reader/DEWebscript.java @@ -1,10 +1,5 @@ package io.swagger.sample.reader; -import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam; -import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri; -import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable; -import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript; -import io.swagger.annotations.*; import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptResponse; @@ -22,19 +17,20 @@ schemes = {SwaggerDefinition.Scheme.HTTP, SwaggerDefinition.Scheme.HTTPS}, tags = {@Tag(name = "core", description = "Core Operations")} ) -@WebScript(description = "Webscript description", baseUri = "/de") +//@WebScript(description = "Webscript description", baseUri = "/de") +@RestController public class DEWebscript { - @Uri("/home") + @GetMapping("/home") @ApiOperation(value = "/home summary", tags = "core", notes = "/home description") public SampleModel simpleGet(@RequestParam String requestParam, @RequestParam(required = false) String requiredParam, - @UriVariable String pathParam, + @RequestParam String pathParam, SampleModel bodyParam) { return new SampleModel(); } - @Uri("/ignoreParams") + @GetMapping("/ignoreParams") public void ignoreParams(WebScriptRequest request, WebScriptResponse responose) { } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9b52131f..e0b9fcdc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ #Mon Nov 04 15:47:31 CET 2019 -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStorePath=wrapper/dists From f88a3ed555f4a38d740c5a9a2806a4fa3ccbbd53 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Thu, 27 Oct 2022 17:22:05 +0300 Subject: [PATCH 04/90] ALFREDAPI-504 Drop custom swagger implementation --- de-swagger-reader/build.gradle | 18 - .../swagger/reader/DESwaggerExtension.java | 62 - .../java/eu/xenit/swagger/reader/Reader.java | 1135 ----------------- .../reader/ext/AbstractSwaggerExtension.java | 54 - .../swagger/reader/ext/SwaggerExtension.java | 18 - .../swagger/reader/ext/SwaggerExtensions.java | 40 - .../swagger/reader/utils/ReaderUtils.java | 135 -- .../io/swagger/sample/reader/DEWebscript.java | 37 - .../sample/reader/DEWebscriptSwaggerTest.java | 111 -- .../sample/reader/ResourceListingIT.java | 52 - .../io/swagger/sample/reader/SampleModel.java | 9 - settings.gradle | 2 - swagger-doc-extractor/README.md | 19 - swagger-doc-extractor/build.gradle | 22 - .../java/eu/xenit/apix/swaggerdoc/Main.java | 19 - 15 files changed, 1733 deletions(-) delete mode 100644 de-swagger-reader/build.gradle delete mode 100644 de-swagger-reader/src/main/java/eu/xenit/swagger/reader/DESwaggerExtension.java delete mode 100644 de-swagger-reader/src/main/java/eu/xenit/swagger/reader/Reader.java delete mode 100644 de-swagger-reader/src/main/java/eu/xenit/swagger/reader/ext/AbstractSwaggerExtension.java delete mode 100644 de-swagger-reader/src/main/java/eu/xenit/swagger/reader/ext/SwaggerExtension.java delete mode 100644 de-swagger-reader/src/main/java/eu/xenit/swagger/reader/ext/SwaggerExtensions.java delete mode 100644 de-swagger-reader/src/main/java/eu/xenit/swagger/reader/utils/ReaderUtils.java delete mode 100644 de-swagger-reader/src/test/java/io/swagger/sample/reader/DEWebscript.java delete mode 100644 de-swagger-reader/src/test/java/io/swagger/sample/reader/DEWebscriptSwaggerTest.java delete mode 100644 de-swagger-reader/src/test/java/io/swagger/sample/reader/ResourceListingIT.java delete mode 100644 de-swagger-reader/src/test/java/io/swagger/sample/reader/SampleModel.java delete mode 100644 swagger-doc-extractor/README.md delete mode 100644 swagger-doc-extractor/build.gradle delete mode 100644 swagger-doc-extractor/src/main/java/eu/xenit/apix/swaggerdoc/Main.java diff --git a/de-swagger-reader/build.gradle b/de-swagger-reader/build.gradle deleted file mode 100644 index 0a2561ec..00000000 --- a/de-swagger-reader/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -group = 'eu.xenit.swagger' -description = 'Xenit Dynamic-extensions Swagger Reader' - -apply plugin: 'osgi' - -dependencies { - implementation group: 'commons-io', name: 'commons-io', version: '2.0.1' - implementation(group: 'io.swagger', name: 'swagger-core', version: swagger_version) { - exclude group: 'org.slf4j', module: 'slf4j-api' - } - compileOnly group: 'org.slf4j', name: 'slf4j-api', version: '1.7.22' - implementation group: 'io.swagger', name: 'swagger-annotations', version: swagger_version - compileOnly(group: 'eu.xenit.de', name: 'annotations', version: de_version) { - transitive = false - } - compileOnly(group: 'org.springframework', name: 'spring-core', version: '3.2.10.RELEASE') - compileOnly(group: 'org.springframework.extensions.surf', name: 'spring-webscripts', version: '5.0.d') -} diff --git a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/DESwaggerExtension.java b/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/DESwaggerExtension.java deleted file mode 100644 index 6e77e5a6..00000000 --- a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/DESwaggerExtension.java +++ /dev/null @@ -1,62 +0,0 @@ -package eu.xenit.swagger.reader; - -import com.fasterxml.jackson.databind.type.ArrayType; -import com.fasterxml.jackson.databind.type.SimpleType; -import eu.xenit.swagger.reader.ext.AbstractSwaggerExtension; -import eu.xenit.swagger.reader.ext.SwaggerExtension; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.PathParameter; -import io.swagger.models.parameters.QueryParameter; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -/** - * Created by Michiel Huygen on 10/03/2016. - */ -public class DESwaggerExtension extends AbstractSwaggerExtension { - - @Override - public List extractParameters(List annotations, Type type, Set typesToSkip, - Iterator chain) { - Class cls = null; - if (type instanceof SimpleType) { - cls = ((SimpleType) type).getRawClass(); // No clue why this happens - } else if (type instanceof Class) { - cls = ((Class) type); - } else if (type instanceof ArrayType) { - cls = ((ArrayType) type).getRawClass(); - } - - if (cls.isAssignableFrom(WebScriptRequest.class) - || cls.isAssignableFrom(WebScriptResponse.class)) { - typesToSkip.add(type); - return Collections.emptyList(); - - } - - for (Annotation ann : annotations) { - if (ann.annotationType().equals(RequestParam.class)) { - RequestParam c = (RequestParam) ann; - - QueryParameter parameter = new QueryParameter(); - parameter.setRequired(c.required()); - parameter.setName(c.value()); - parameter.setType("string"); //TODO - - return Collections.singletonList((Parameter) parameter); - - } - } - - return Collections.emptyList(); - // SHould i call parent? - // return super.extractParameters(annotations, type, typesToSkip, chain); - } -} diff --git a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/Reader.java b/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/Reader.java deleted file mode 100644 index 86c6021a..00000000 --- a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/Reader.java +++ /dev/null @@ -1,1135 +0,0 @@ -/** - * Copyright 2016 SmartBear Software - *

- * 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 eu.xenit.swagger.reader; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; -import eu.xenit.swagger.reader.ext.SwaggerExtension; -import eu.xenit.swagger.reader.ext.SwaggerExtensions; -import eu.xenit.swagger.reader.utils.ReaderUtils; -import io.swagger.annotations.*; -import io.swagger.annotations.Info; -import io.swagger.converter.ModelConverters; -import io.swagger.models.Contact; -import io.swagger.models.ExternalDocs; -import io.swagger.models.License; -import io.swagger.models.*; -import io.swagger.models.Tag; -import io.swagger.models.parameters.*; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.RefProperty; -import io.swagger.util.BaseReaderUtils; -import io.swagger.util.ParameterProcessor; -import io.swagger.util.PathUtils; -import io.swagger.util.ReflectionUtils; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.LocalVariableTableParameterNameDiscoverer; - -//import javax.ws.rs.Consumes; -//import javax.ws.rs.HttpMethod; -//import javax.ws.rs.Produces; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.*; - -public class Reader { - - private static final Logger LOGGER = LoggerFactory.getLogger(Reader.class); - private static final String SUCCESSFUL_OPERATION = "successful operation"; - private static final String PATH_DELIMITER = "/"; - - //private final ReaderConfig config; - private Swagger swagger; - private String[] ignoredRoutes = new String[0]; - - public Reader() { - this(null); - } - - public Reader(Swagger swagger) { - this.swagger = swagger == null ? new Swagger() : swagger; - } - - private static Class getClassArgument(Type cls) { - if (cls instanceof ParameterizedType) { - final ParameterizedType parameterized = (ParameterizedType) cls; - final Type[] args = parameterized.getActualTypeArguments(); - if (args.length != 1) { - LOGGER.error(String.format("Unexpected class definition: %s", cls)); - return null; - } - final Type first = args[0]; - if (first instanceof Class) { - return (Class) first; - } else { - return null; - } - } else { - LOGGER.error(String.format("Unknown class definition: %s", cls)); - return null; - } - } - -// public Reader(Swagger swagger){//, ReaderConfig config) { -// this.swagger = swagger == null ? new Swagger() : swagger; -// //this.config = new DefaultReaderConfig(config); -// } - - private static Set parseSchemes(String schemes) { - final Set result = EnumSet.noneOf(Scheme.class); - for (String item : StringUtils.trimToEmpty(schemes).split(",")) { - final Scheme scheme = Scheme.forValue(StringUtils.trimToNull(item)); - if (scheme != null) { - result.add(scheme); - } - } - return result; - } - - private static boolean isVoid(Type type) { - final Class cls = TypeFactory.defaultInstance().constructType(type).getRawClass(); - return Void.class.isAssignableFrom(cls) || Void.TYPE.isAssignableFrom(cls); - } - - private static boolean isValidResponse(Type type) { - if (type == null) { - return false; - } - final JavaType javaType = TypeFactory.defaultInstance().constructType(type); - if (isVoid(javaType)) { - return false; - } - final Class cls = javaType.getRawClass(); - //TODO: return !javax.ws.rs.core.Response.class.isAssignableFrom(cls) && !isResourceClass(cls); - return !isResourceClass(cls); - } - - private static boolean isResourceClass(Class cls) { - return cls.getAnnotation(Api.class) != null; - } - - /** - * Scans a set of classes for both ReaderListeners and Swagger annotations. All found listeners will - * be instantiated before any of the classes are scanned for Swagger annotations - so they can be invoked - * accordingly. - * - * @param classes a set of classes to scan - * @return the generated Swagger definition - */ - - public Swagger read(Set> classes) { - // process SwaggerDefinitions first - so we get tags in desired order - for (Class cls : classes) { - SwaggerDefinition swaggerDefinition = cls.getAnnotation(SwaggerDefinition.class); - if (swaggerDefinition != null) { - readSwaggerConfig(cls, swaggerDefinition); - } - } - - for (Class cls : classes) { - read(cls, "", null, false, new String[0], new String[0], new HashMap(), - new ArrayList(), new HashSet>()); - } - - return swagger; - } - - public Swagger getSwagger() { - return this.swagger; - } - - /** - * Scans a single class for Swagger annotations - does not invoke ReaderListeners - */ - - public Swagger read(Class cls) { - - SwaggerDefinition swaggerDefinition = cls.getAnnotation(SwaggerDefinition.class); - if (swaggerDefinition != null) { - readSwaggerConfig(cls, swaggerDefinition); - } - - return read(cls, "", null, false, new String[0], new String[0], new HashMap(), - new ArrayList(), new HashSet>()); - } - - protected Swagger read(Class cls, String parentPath, String parentMethod, boolean isSubresource, - String[] parentConsumes, String[] parentProduces, Map parentTags, - List parentParameters) { - return read(cls, parentPath, parentMethod, isSubresource, parentConsumes, parentProduces, parentTags, - parentParameters, new HashSet>()); - } - - private Swagger read(Class cls, String parentPath, String parentMethod, boolean isSubresource, - String[] parentConsumes, String[] parentProduces, Map parentTags, - List parentParameters, Set> scannedResources) { - Map globalScopes = new HashMap(); - - Map tags = new HashMap(); - List securities = new ArrayList(); - - String[] consumes = new String[0]; - String[] produces = new String[0]; - final Set globalSchemes = EnumSet.noneOf(Scheme.class); - - Api api = (Api) cls.getAnnotation(Api.class); - WebScript webscript = (WebScript) cls.getAnnotation(WebScript.class); - - boolean hasPathAnnotation = false;//TODO: (ReflectionUtils.getAnnotation(cls, javax.ws.rs.Path.class) != null); - boolean hasApiAnnotation = (api != null); - boolean isApiHidden = hasApiAnnotation && api.hidden(); - boolean hasDEWebscript = webscript != null; - - // class readable only if annotated with @Path or isSubresource, or and @Api not hidden - boolean classReadable = (hasPathAnnotation || isSubresource) && !isApiHidden; - - // readable if classReadable or (scanAllResources true in config and @Api not hidden) - boolean readable = classReadable || hasDEWebscript;//&& config.isScanAllResources()); - - if (isApiHidden) { - return swagger; - } - - if (!readable) { - return swagger; - } - Tag webscriptTag = null; - - if (webscript != null) { - - parentPath += webscript.baseUri(); - - Tag tag = new Tag(); - tag.setDescription(webscript.description()); - -// cls.getAnnotation(webscript) -// String webscriptTagName = cls.getSimpleName(); -// String[] cutOff = {"webscript","webscript1"}; -// for(int i =0;i 0; - String name = tagHasValidNameProperty ? webscript.value() : cls.getSimpleName(); - tag.setName(name); - swagger.addTag(tag); - webscriptTag = tag; - - - } - if (hasApiAnnotation && api.tags() != null && api.tags().length > 0) { - webscriptTag = null; // Don't use webscripttags when custom is specified - } - - // api readable only if @Api present; cannot be hidden because checked in classReadable. - boolean apiReadable = hasApiAnnotation; - - if (apiReadable) { - // the value will be used as a tag for 2.0 UNLESS a Tags annotation is present - Set tagStrings = extractTags(api); - for (String tagString : tagStrings) { - Tag tag = new Tag().name(tagString); - tags.put(tagString, tag); - } - for (String tagName : tags.keySet()) { - swagger.tag(tags.get(tagName)); - } - - if (!api.produces().isEmpty()) { - produces = new String[]{api.produces()}; - /*} else if (cls.getAnnotation(Produces.class) != null) { - produces = ReaderUtils.splitContentValues(cls.getAnnotation(Produces.class).value());*/ - } - if (!api.consumes().isEmpty()) { - consumes = new String[]{api.consumes()}; - /*} else if (cls.getAnnotation(Consumes.class) != null) { - consumes = ReaderUtils.splitContentValues(cls.getAnnotation(Consumes.class).value());*/ - } - globalSchemes.addAll(parseSchemes(api.protocols())); - Authorization[] authorizations = api.authorizations(); - - for (Authorization auth : authorizations) { - if (auth.value() != null && !"".equals(auth.value())) { - SecurityRequirement security = new SecurityRequirement(); - security.setName(auth.value()); - AuthorizationScope[] scopes = auth.scopes(); - for (AuthorizationScope scope : scopes) { - if (scope.scope() != null && !"".equals(scope.scope())) { - security.addScope(scope.scope()); - } - } - securities.add(security); - } - } - } - - if (readable) { - - if (isSubresource) { - if (parentTags != null) { - tags.putAll(parentTags); - } - } - // merge consumes, produces - - // look for method-level annotated properties - - // handle sub-resources by looking at return type - - final List globalParameters = new ArrayList(); - - // look for constructor-level annotated properties - globalParameters.addAll(ReaderUtils.collectConstructorParameters(cls, swagger)); - - // look for field-level annotated properties - globalParameters.addAll(ReaderUtils.collectFieldParameters(cls, swagger)); - - // parse the method - //final javax.ws.rs.Path apiPath = ReflectionUtils.getAnnotation(cls, javax.ws.rs.Path.class); - Method methods[] = cls.getMethods(); - for (Method method : methods) { - if (ReflectionUtils.isOverriddenMethod(method, cls)) { - continue; - } - //javax.ws.rs.Path methodPath = ReflectionUtils.getAnnotation(method, javax.ws.rs.Path.class); - - String operationPath = getPath(method, parentPath); - Map regexMap = new HashMap(); - operationPath = PathUtils.parsePath(operationPath, regexMap); - if (operationPath != null) { - if (isIgnored(operationPath)) { - continue; - } - - final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); - String httpMethod = extractOperationMethod(apiOperation, method, SwaggerExtensions.chain()); - - Operation operation = null; - //if(apiOperation != null || config.isScanAllResources() || httpMethod != null || methodPath != null) { - if (apiOperation != null || httpMethod != null) {//|| methodPath != null) { - operation = parseMethod(cls, method, globalParameters); - } - if (operation == null) { - continue; - } - if (parentParameters != null) { - for (Parameter param : parentParameters) { - operation.parameter(param); - } - } - for (Parameter param : operation.getParameters()) { - if (regexMap.get(param.getName()) != null) { - String pattern = regexMap.get(param.getName()); - param.setPattern(pattern); - } - } - - if (apiOperation != null) { - for (Scheme scheme : parseSchemes(apiOperation.protocols())) { - operation.scheme(scheme); - } - } - - if (operation.getSchemes() == null || operation.getSchemes().isEmpty()) { - for (Scheme scheme : globalSchemes) { - operation.scheme(scheme); - } - } - - String[] apiConsumes = consumes; - if (parentConsumes != null) { - Set both = new HashSet(Arrays.asList(apiConsumes)); - both.addAll(new HashSet(Arrays.asList(parentConsumes))); - if (operation.getConsumes() != null) { - both.addAll(new HashSet(operation.getConsumes())); - } - apiConsumes = both.toArray(new String[both.size()]); - } - - String[] apiProduces = produces; - if (parentProduces != null) { - Set both = new HashSet(Arrays.asList(apiProduces)); - both.addAll(new HashSet(Arrays.asList(parentProduces))); - if (operation.getProduces() != null) { - both.addAll(new HashSet(operation.getProduces())); - } - apiProduces = both.toArray(new String[both.size()]); - } - final Class subResource = getSubResourceWithJaxRsSubresourceLocatorSpecs(method); - if (subResource != null && !scannedResources.contains(subResource)) { - scannedResources.add(subResource); - read(subResource, operationPath, httpMethod, true, apiConsumes, apiProduces, tags, - operation.getParameters(), scannedResources); - // remove the sub resource so that it can visit it later in another path - // but we have a room for optimization in the future to reuse the scanned result - // by caching the scanned resources in the reader instance to avoid actual scanning - // the the resources again - scannedResources.remove(subResource); - } - - // can't continue without a valid http method - httpMethod = httpMethod == null ? parentMethod : httpMethod; - if (httpMethod != null) { - if (apiOperation != null) { - boolean hasExplicitTag = false; - for (String tag : apiOperation.tags()) { - if (!"".equals(tag)) { - operation.tag(tag); - swagger.tag(new Tag().name(tag)); - } - } - - operation.getVendorExtensions() - .putAll(BaseReaderUtils.parseExtensions(apiOperation.extensions())); - } - - if (operation.getConsumes() == null) { - for (String mediaType : apiConsumes) { - operation.consumes(mediaType); - } - } - if (operation.getProduces() == null) { - for (String mediaType : apiProduces) { - operation.produces(mediaType); - } - } - - if (operation.getTags() == null) { - for (String tagString : tags.keySet()) { - operation.tag(tagString); - } - } - - if (webscriptTag != null) { - operation.tag(webscriptTag.getName()); - } - - // Only add global @Api securities if operation doesn't already have more specific securities - if (operation.getSecurity() == null) { - for (SecurityRequirement security : securities) { - operation.security(security); - } - } - - Path path = swagger.getPath(operationPath); - if (path == null) { - path = new Path(); - swagger.path(operationPath, path); - } - path.set(httpMethod, operation); - - readImplicitParameters(method, operation); - } - } - } - } - - return swagger; - } - - private void readImplicitParameters(Method method, Operation operation) { - ApiImplicitParams implicitParams = method.getAnnotation(ApiImplicitParams.class); - if (implicitParams != null && implicitParams.value().length > 0) { - for (ApiImplicitParam param : implicitParams.value()) { - Parameter p = readImplicitParam(param); - if (p != null) { - operation.addParameter(p); - } - } - } - } - - protected Parameter readImplicitParam(ApiImplicitParam param) { - final Parameter p; - if (param.paramType().equalsIgnoreCase("path")) { - p = new PathParameter(); - } else if (param.paramType().equalsIgnoreCase("query")) { - p = new QueryParameter(); - } else if (param.paramType().equalsIgnoreCase("form") || param.paramType().equalsIgnoreCase("formData")) { - p = new FormParameter(); - } else if (param.paramType().equalsIgnoreCase("body")) { - p = null; - } else if (param.paramType().equalsIgnoreCase("header")) { - p = new HeaderParameter(); - } else { - LOGGER.warn("Unkown implicit parameter type: [" + param.paramType() + "]"); - return null; - } - - Type type; - - try { - if (param.dataType().equals("file")) { - type = java.io.File.class; - } else { - type = Class.forName(param.dataType()); - } - } catch (ClassNotFoundException e) { - LOGGER.debug("Class not found, using native swagger method. dataType: " + param.dataType()); - type = ReflectionUtils.typeFromString(param.dataType()); - } - - return ParameterProcessor.applyAnnotations(swagger, p, type == null ? String.class : type, - Arrays.asList(param)); - } - - protected void readSwaggerConfig(Class cls, SwaggerDefinition config) { - - if (!config.basePath().isEmpty()) { - swagger.setBasePath(config.basePath()); - } - - if (!config.host().isEmpty()) { - swagger.setHost(config.host()); - } - - readInfoConfig(config); - - for (String consume : config.consumes()) { - if (StringUtils.isNotEmpty(consume)) { - swagger.addConsumes(consume); - } - } - - for (String produce : config.produces()) { - if (StringUtils.isNotEmpty(produce)) { - swagger.addProduces(produce); - } - } - - if (!config.externalDocs().value().isEmpty()) { - ExternalDocs externalDocs = swagger.getExternalDocs(); - if (externalDocs == null) { - externalDocs = new ExternalDocs(); - swagger.setExternalDocs(externalDocs); - } - - externalDocs.setDescription(config.externalDocs().value()); - - if (!config.externalDocs().url().isEmpty()) { - externalDocs.setUrl(config.externalDocs().url()); - } - } - - for (io.swagger.annotations.Tag tagConfig : config.tags()) { - if (!tagConfig.name().isEmpty()) { - Tag tag = new Tag(); - tag.setName(tagConfig.name()); - tag.setDescription(tagConfig.description()); - - if (!tagConfig.externalDocs().value().isEmpty()) { - tag.setExternalDocs(new ExternalDocs(tagConfig.externalDocs().value(), - tagConfig.externalDocs().url())); - } - - tag.getVendorExtensions().putAll(BaseReaderUtils.parseExtensions(tagConfig.extensions())); - - swagger.addTag(tag); - } - } - - for (SwaggerDefinition.Scheme scheme : config.schemes()) { - if (scheme != SwaggerDefinition.Scheme.DEFAULT) { - swagger.addScheme(Scheme.forValue(scheme.name())); - } - } - } - - protected void readInfoConfig(SwaggerDefinition config) { - Info infoConfig = config.info(); - io.swagger.models.Info info = swagger.getInfo(); - if (info == null) { - info = new io.swagger.models.Info(); - swagger.setInfo(info); - } - - if (!infoConfig.description().isEmpty()) { - info.setDescription(infoConfig.description()); - } - - if (!infoConfig.termsOfService().isEmpty()) { - info.setTermsOfService(infoConfig.termsOfService()); - } - - if (!infoConfig.title().isEmpty()) { - info.setTitle(infoConfig.title()); - } - - if (!infoConfig.version().isEmpty()) { - info.setVersion(infoConfig.version()); - } - - if (!infoConfig.contact().name().isEmpty()) { - Contact contact = info.getContact(); - if (contact == null) { - contact = new Contact(); - info.setContact(contact); - } - - contact.setName(infoConfig.contact().name()); - if (!infoConfig.contact().email().isEmpty()) { - contact.setEmail(infoConfig.contact().email()); - } - - if (!infoConfig.contact().url().isEmpty()) { - contact.setUrl(infoConfig.contact().url()); - } - } - - if (!infoConfig.license().name().isEmpty()) { - License license = info.getLicense(); - if (license == null) { - license = new License(); - info.setLicense(license); - } - - license.setName(infoConfig.license().name()); - if (!infoConfig.license().url().isEmpty()) { - license.setUrl(infoConfig.license().url()); - } - } - - info.getVendorExtensions().putAll(BaseReaderUtils.parseExtensions(infoConfig.extensions())); - } - - protected Class getSubResource(Method method) { - final Class rawType = method.getReturnType(); - final Class type; - if (Class.class.equals(rawType)) { - type = getClassArgument(method.getGenericReturnType()); - if (type == null) { - return null; - } - } else { - type = rawType; - } - - if (type.getAnnotation(Api.class) != null) { - return type; - } - - // For sub-resources that are not annotated with @Api, look for any HttpMethods. - for (Method m : type.getMethods()) { - if (extractOperationMethod(null, m, null) != null) { - return type; - } - } - - return null; - } - - //TODO: -// String getPath(javax.ws.rs.Path classLevelPath, javax.ws.rs.Path methodLevelPath, String parentPath) { -// if (classLevelPath == null && methodLevelPath == null && StringUtils.isEmpty(parentPath)) { -// return null; -// } -// StringBuilder b = new StringBuilder(); -// if (parentPath != null && !"".equals(parentPath) && !"/".equals(parentPath)) { -// if (!parentPath.startsWith("/")) { -// parentPath = "/" + parentPath; -// } -// if (parentPath.endsWith("/")) { -// parentPath = parentPath.substring(0, parentPath.length() - 1); -// } -// -// b.append(parentPath); -// } -// if (classLevelPath != null) { -// b.append(classLevelPath.value()); -// } -// if (methodLevelPath != null && !"/".equals(methodLevelPath.value())) { -// String methodPath = methodLevelPath.value(); -// if (!methodPath.startsWith("/") && !b.toString().endsWith("/")) { -// b.append("/"); -// } -// if (methodPath.endsWith("/")) { -// methodPath = methodPath.substring(0, methodPath.length() - 1); -// } -// b.append(methodPath); -// } -// String output = b.toString(); -// if (!output.startsWith("/")) { -// output = "/" + output; -// } -// if (output.endsWith("/") && output.length() > 1) { -// return output.substring(0, output.length() - 1); -// } else { -// return output; -// } -// } - - protected Class getSubResourceWithJaxRsSubresourceLocatorSpecs(Method method) { - final Class rawType = method.getReturnType(); - final Class type; - if (Class.class.equals(rawType)) { - type = getClassArgument(method.getGenericReturnType()); - if (type == null) { - return null; - } - } else { - type = rawType; - } - - //TODO: DE? - /*if (method.getAnnotation(javax.ws.rs.Path.class) != null) { - if (extractOperationMethod(null, method, null) == null) { - return type; - } - }*/ - return null; - } - - protected Set extractTags(Api api) { - Set output = new LinkedHashSet(); - - boolean hasExplicitTags = false; - for (String tag : api.tags()) { - if (!"".equals(tag)) { - hasExplicitTags = true; - output.add(tag); - } - } - if (!hasExplicitTags) { - // derive tag from api path + description - String tagString = api.value().replace("/", ""); - if (!"".equals(tagString)) { - output.add(tagString); - } - } - return output; - } - - private String getPath(Method method, String parentPath) { - // DE - Uri uri = (Uri) method.getAnnotation(Uri.class); - if (uri == null) { - return null; - } - - if (uri.value().length != 1) { - throw new RuntimeException("Should have a single path for uri!" + uri.value()); - } - return parentPath + uri.value()[0]; -// -// if (classLevelPath == null && methodLevelPath == null && StringUtils.isEmpty(parentPath)) { -// return null; -// } -// StringBuilder b = new StringBuilder(); -// if (parentPath != null && !"".equals(parentPath) && !"/".equals(parentPath)) { -// if (!parentPath.startsWith("/")) { -// parentPath = "/" + parentPath; -// } -// if (parentPath.endsWith("/")) { -// parentPath = parentPath.substring(0, parentPath.length() - 1); -// } -// -// b.append(parentPath); -// } -// if (classLevelPath != null) { -// b.append(classLevelPath.value()); -// } -// if (methodLevelPath != null && !"/".equals(methodLevelPath.value())) { -// String methodPath = methodLevelPath.value(); -// if (!methodPath.startsWith("/") && !b.toString().endsWith("/")) { -// b.append("/"); -// } -// if (methodPath.endsWith("/")) { -// methodPath = methodPath.substring(0, methodPath.length() - 1); -// } -// b.append(methodPath); -// } -// String output = b.toString(); -// if (!output.startsWith("/")) { -// output = "/" + output; -// } -// if (output.endsWith("/") && output.length() > 1) { -// return output.substring(0, output.length() - 1); -// } else { -// return output; -// } - } - - private Map parseResponseHeaders(ResponseHeader[] headers) { - Map responseHeaders = null; - if (headers != null && headers.length > 0) { - for (ResponseHeader header : headers) { - String name = header.name(); - if (!"".equals(name)) { - if (responseHeaders == null) { - responseHeaders = new HashMap(); - } - String description = header.description(); - Class cls = header.response(); - - if (!isVoid(cls)) { - final Property property = ModelConverters.getInstance().readAsProperty(cls); - if (property != null) { - Property responseProperty = ContainerWrapper - .wrapContainer(header.responseContainer(), property, - ContainerWrapper.ARRAY, ContainerWrapper.LIST, ContainerWrapper.SET); - responseProperty.setDescription(description); - responseHeaders.put(name, responseProperty); - appendModels(cls); - } - } - } - } - } - return responseHeaders; - } - - /*private String getHttpMethodFromCustomAnnotations(Method method) { - for(Annotation methodAnnotation : method.getAnnotations()){ - HttpMethod httpMethod = methodAnnotation.annotationType().getAnnotation(HttpMethod.class); - if(httpMethod != null) { - return httpMethod.value().toLowerCase(); - } - } - return null; - }*/ - - private Operation parseMethod(Class cls, Method method, List globalParameters) { - Operation operation = new Operation(); - - ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); - ApiResponses responseAnnotation = ReflectionUtils.getAnnotation(method, ApiResponses.class); - - String operationId = method.getName(); - String responseContainer = null; - - Type responseType = null; - Map defaultResponseHeaders = new HashMap(); - - if (apiOperation != null) { - if (apiOperation.hidden()) { - return null; - } - if (!"".equals(apiOperation.nickname())) { - operationId = apiOperation.nickname(); - } - - defaultResponseHeaders = parseResponseHeaders(apiOperation.responseHeaders()); - - operation - .summary(apiOperation.value()) - .description(apiOperation.notes()); - - if (apiOperation.response() != null && !isVoid(apiOperation.response())) { - responseType = apiOperation.response(); - } - if (!"".equals(apiOperation.responseContainer())) { - responseContainer = apiOperation.responseContainer(); - } - if (apiOperation.authorizations() != null) { - List securities = new ArrayList(); - for (Authorization auth : apiOperation.authorizations()) { - if (auth.value() != null && !"".equals(auth.value())) { - SecurityRequirement security = new SecurityRequirement(); - security.setName(auth.value()); - AuthorizationScope[] scopes = auth.scopes(); - for (AuthorizationScope scope : scopes) { - if (scope.scope() != null && !"".equals(scope.scope())) { - security.addScope(scope.scope()); - } - } - securities.add(security); - } - } - if (securities.size() > 0) { - for (SecurityRequirement sec : securities) { - operation.security(sec); - } - } - } - if (apiOperation.consumes() != null && !apiOperation.consumes().isEmpty()) { - operation.consumes(apiOperation.consumes()); - } - if (apiOperation.produces() != null && !apiOperation.produces().isEmpty()) { - operation.produces(apiOperation.produces()); - } - } - - if (apiOperation != null && StringUtils.isNotEmpty(apiOperation.responseReference())) { - Response response = new Response().description(SUCCESSFUL_OPERATION); - response.schema(new RefProperty(apiOperation.responseReference())); - operation.addResponse(String.valueOf(apiOperation.code()), response); - } else if (responseType == null) { - // pick out response from method declaration - LOGGER.debug("picking up response class from method " + method); - responseType = method.getGenericReturnType(); - } - if (isValidResponse(responseType)) { - final Property property = ModelConverters.getInstance().readAsProperty(responseType); - if (property != null) { - final Property responseProperty = ContainerWrapper.wrapContainer(responseContainer, property); - final int responseCode = apiOperation == null ? 200 : apiOperation.code(); - operation.response(responseCode, - new Response().description(SUCCESSFUL_OPERATION).schema(responseProperty) - .headers(defaultResponseHeaders)); - appendModels(responseType); - } - } - - operation.operationId(operationId); - -// if (apiOperation != null && apiOperation.consumes() != null && apiOperation.consumes().isEmpty()) { -// final Consumes consumes = ReflectionUtils.getAnnotation(method, Consumes.class); -// if (consumes != null) { -// for (String mediaType : ReaderUtils.splitContentValues(consumes.value())) { -// operation.consumes(mediaType); -// } -// } -// } -// -// if (apiOperation != null && apiOperation.produces() != null && apiOperation.produces().isEmpty()) { -// final Produces produces = ReflectionUtils.getAnnotation(method, Produces.class); -// if (produces != null) { -// for (String mediaType : ReaderUtils.splitContentValues(produces.value())) { -// operation.produces(mediaType); -// } -// } -// } - - List apiResponses = new ArrayList(); - if (responseAnnotation != null) { - apiResponses.addAll(Arrays.asList(responseAnnotation.value())); - } - - Class[] exceptionTypes = method.getExceptionTypes(); - for (Class exceptionType : exceptionTypes) { - ApiResponses exceptionResponses = ReflectionUtils.getAnnotation(exceptionType, ApiResponses.class); - if (exceptionResponses != null) { - apiResponses.addAll(Arrays.asList(exceptionResponses.value())); - } - } - - for (ApiResponse apiResponse : apiResponses) { - Map responseHeaders = parseResponseHeaders(apiResponse.responseHeaders()); - - Response response = new Response() - .description(apiResponse.message()) - .headers(responseHeaders); - - if (apiResponse.code() == 0) { - operation.defaultResponse(response); - } else { - operation.response(apiResponse.code(), response); - } - - if (StringUtils.isNotEmpty(apiResponse.reference())) { - - response.schema(new RefProperty(apiResponse.reference())); - } else if (!isVoid(apiResponse.response())) { - responseType = apiResponse.response(); - final Property property = ModelConverters.getInstance().readAsProperty(responseType); - if (property != null) { - response.schema(ContainerWrapper.wrapContainer(apiResponse.responseContainer(), property)); - appendModels(responseType); - } - } - } - if (ReflectionUtils.getAnnotation(method, Deprecated.class) != null) { - operation.setDeprecated(true); - } - - // process parameters - for (Parameter globalParameter : globalParameters) { - operation.parameter(globalParameter); - } - - Type[] genericParameterTypes = method.getGenericParameterTypes(); - Annotation[][] paramAnnotations = method.getParameterAnnotations(); - LocalVariableTableParameterNameDiscoverer disco = new LocalVariableTableParameterNameDiscoverer(); - String[] parameterNames = disco.getParameterNames(method); - for (int i = 0; i < genericParameterTypes.length; i++) { - final Type type = TypeFactory.defaultInstance().constructType(genericParameterTypes[i], cls); - List parameters = getParameters(type, Arrays.asList(paramAnnotations[i])); - - for (Parameter parameter : parameters) { - if (parameter.getName().equals("")) { - parameter.setName(parameterNames[i]); - } - operation.parameter(parameter); - } - } - - if (operation.getResponses() == null) { - Response response = new Response().description(SUCCESSFUL_OPERATION); - operation.defaultResponse(response); - } - return operation; - } - - private List getParameters(Type type, List annotations) { - final Iterator chain = SwaggerExtensions.chain(); - if (!chain.hasNext()) { - return Collections.emptyList(); - } - LOGGER.debug("getParameters for " + type); - Set typesToSkip = new HashSet(); - final SwaggerExtension extension = chain.next(); - LOGGER.debug("trying extension " + extension); - - final List parameters = extension.extractParameters(annotations, type, typesToSkip, chain); - if (parameters.size() > 0) { - final List processed = new ArrayList(parameters.size()); - for (Parameter parameter : parameters) { - if (ParameterProcessor.applyAnnotations(swagger, parameter, type, annotations) != null) { - processed.add(parameter); - } - } - return processed; - } else { - LOGGER.debug("no parameter found, looking at body params"); - final List body = new ArrayList(); - if (!typesToSkip.contains(type)) { - Parameter param = ParameterProcessor.applyAnnotations(swagger, null, type, annotations); - if (param != null) { - body.add(param); - } - } - return body; - } - } - - public String extractOperationMethod(ApiOperation apiOperation, Method method, Iterator chain) { - if (apiOperation != null && apiOperation.httpMethod() != null && !"".equals(apiOperation.httpMethod())) { - return apiOperation.httpMethod().toLowerCase(); - //TODO add DE here! -// } else if (method.getAnnotation(javax.ws.rs.GET.class) != null) { -// return "get"; -// } else if (method.getAnnotation(javax.ws.rs.PUT.class) != null) { -// return "put"; -// } else if (method.getAnnotation(javax.ws.rs.POST.class) != null) { -// return "post"; -// } else if (method.getAnnotation(javax.ws.rs.DELETE.class) != null) { -// return "delete"; -// } else if (method.getAnnotation(javax.ws.rs.OPTIONS.class) != null) { -// return "options"; -// } else if (method.getAnnotation(javax.ws.rs.HEAD.class) != null) { -// return "head"; -// } else if (method.getAnnotation(PATCH.class) != null) { -// return "patch"; -// } else if (method.getAnnotation(HttpMethod.class) != null) { -// HttpMethod httpMethod = method.getAnnotation(HttpMethod.class); -// return httpMethod.value().toLowerCase(); - /*} else if(!StringUtils.isEmpty(getHttpMethodFromCustomAnnotations(method))) { - return getHttpMethodFromCustomAnnotations(method);*/ - } - - Uri uri = (Uri) method.getAnnotation(Uri.class); - if (uri != null) { - return uri.method().toString().toLowerCase(); - } - - if ((ReflectionUtils.getOverriddenMethod(method)) != null) { - return extractOperationMethod(apiOperation, ReflectionUtils.getOverriddenMethod(method), chain); - } else if (chain != null && chain.hasNext()) { - return chain.next().extractOperationMethod(apiOperation, method, chain); - } else { - return null; - } - } - - private void appendModels(Type type) { - final Map models = ModelConverters.getInstance().readAll(type); - for (Map.Entry entry : models.entrySet()) { - swagger.model(entry.getKey(), entry.getValue()); - } - } - - private boolean isIgnored(String path) { - for (String item : getIgnoredRoutes()) { - final int length = item.length(); - if (path.startsWith(item) && (path.length() == length || path.startsWith(PATH_DELIMITER, length))) { - return true; - } - } - return false; - } - - public String[] getIgnoredRoutes() { - return ignoredRoutes; - } - - public void setIgnoredRoutes(String[] ignoredRoutes) { - this.ignoredRoutes = ignoredRoutes; - } - - - enum ContainerWrapper { - LIST("list") { - @Override - protected Property doWrap(Property property) { - return new ArrayProperty(property); - } - }, - ARRAY("array") { - @Override - protected Property doWrap(Property property) { - return new ArrayProperty(property); - } - }, - MAP("map") { - @Override - protected Property doWrap(Property property) { - return new MapProperty(property); - } - }, - SET("set") { - @Override - protected Property doWrap(Property property) { - ArrayProperty arrayProperty = new ArrayProperty(property); - arrayProperty.setUniqueItems(true); - return arrayProperty; - } - }; - - private final String container; - - ContainerWrapper(String container) { - this.container = container; - } - - public static Property wrapContainer(String container, Property property, ContainerWrapper... allowed) { - final Set tmp = - allowed.length > 0 ? EnumSet.copyOf(Arrays.asList(allowed)) : EnumSet.allOf(ContainerWrapper.class); - for (ContainerWrapper wrapper : tmp) { - final Property prop = wrapper.wrap(container, property); - if (prop != null) { - return prop; - } - } - return property; - } - - public Property wrap(String container, Property property) { - if (this.container.equalsIgnoreCase(container)) { - return doWrap(property); - } - return null; - } - - protected abstract Property doWrap(Property property); - } -} diff --git a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/ext/AbstractSwaggerExtension.java b/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/ext/AbstractSwaggerExtension.java deleted file mode 100644 index 2811ead0..00000000 --- a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/ext/AbstractSwaggerExtension.java +++ /dev/null @@ -1,54 +0,0 @@ -package eu.xenit.swagger.reader.ext; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; -import io.swagger.annotations.ApiOperation; -import io.swagger.models.parameters.Parameter; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -public abstract class AbstractSwaggerExtension implements SwaggerExtension { - - - public String extractOperationMethod(ApiOperation apiOperation, Method method, Iterator chain) { - if (chain.hasNext()) { - return chain.next().extractOperationMethod(apiOperation, method, chain); - } else { - return null; - } - } - - - public List extractParameters(List annotations, Type type, Set typesToSkip, - Iterator chain) { - if (chain.hasNext()) { - return chain.next().extractParameters(annotations, type, typesToSkip, chain); - } else { - return Collections.emptyList(); - } - } - - protected boolean shouldIgnoreClass(Class cls) { - return false; - } - - protected boolean shouldIgnoreType(Type type, Set typesToSkip) { - if (typesToSkip.contains(type)) { - return true; - } - if (shouldIgnoreClass(constructType(type).getRawClass())) { - typesToSkip.add(type); - return true; - } - return false; - } - - protected JavaType constructType(Type type) { - return TypeFactory.defaultInstance().constructType(type); - } -} diff --git a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/ext/SwaggerExtension.java b/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/ext/SwaggerExtension.java deleted file mode 100644 index ad15b5d7..00000000 --- a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/ext/SwaggerExtension.java +++ /dev/null @@ -1,18 +0,0 @@ -package eu.xenit.swagger.reader.ext; - -import io.swagger.annotations.ApiOperation; -import io.swagger.models.parameters.Parameter; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -public interface SwaggerExtension { - - String extractOperationMethod(ApiOperation apiOperation, Method method, Iterator chain); - - List extractParameters(List annotations, Type type, Set typesToSkip, - Iterator chain); -} diff --git a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/ext/SwaggerExtensions.java b/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/ext/SwaggerExtensions.java deleted file mode 100644 index 0ff600d8..00000000 --- a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/ext/SwaggerExtensions.java +++ /dev/null @@ -1,40 +0,0 @@ -package eu.xenit.swagger.reader.ext; - -import eu.xenit.swagger.reader.DESwaggerExtension; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ServiceLoader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SwaggerExtensions { - - static Logger LOGGER = LoggerFactory.getLogger(SwaggerExtensions.class); - - private static List extensions = null; - - static { - extensions = new ArrayList(); - ServiceLoader loader = ServiceLoader.load(SwaggerExtension.class); - Iterator itr = loader.iterator(); - while (itr.hasNext()) { - SwaggerExtension ext = itr.next(); - LOGGER.debug("adding extension " + ext); - extensions.add(ext); - } - extensions.add(new DESwaggerExtension()); - } - - public static List getExtensions() { - return extensions; - } - - public static void setExtensions(List ext) { - extensions = ext; - } - - public static Iterator chain() { - return extensions.iterator(); - } -} \ No newline at end of file diff --git a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/utils/ReaderUtils.java b/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/utils/ReaderUtils.java deleted file mode 100644 index 09cdca04..00000000 --- a/de-swagger-reader/src/main/java/eu/xenit/swagger/reader/utils/ReaderUtils.java +++ /dev/null @@ -1,135 +0,0 @@ -package eu.xenit.swagger.reader.utils; - -import com.google.common.base.Splitter; -import com.google.common.collect.Iterables; -import eu.xenit.swagger.reader.ext.SwaggerExtension; -import eu.xenit.swagger.reader.ext.SwaggerExtensions; -import io.swagger.models.Swagger; -import io.swagger.models.parameters.Parameter; -import io.swagger.util.ParameterProcessor; -import io.swagger.util.ReflectionUtils; -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -public class ReaderUtils { - - /** - * Collects constructor-level parameters from class. - * - * @param cls is a class for collecting - * @param swagger is the instance of the Swagger - * @return the collection of supported parameters - */ - public static List collectConstructorParameters(Class cls, Swagger swagger) { - if (cls.isLocalClass() || (cls.isMemberClass() && !Modifier.isStatic(cls.getModifiers()))) { - return Collections.emptyList(); - } - - List selected = Collections.emptyList(); - int maxParamsCount = 0; - - for (Constructor constructor : cls.getDeclaredConstructors()) { - if (!ReflectionUtils.isConstructorCompatible(constructor) - && !ReflectionUtils.isInject(Arrays.asList(constructor.getDeclaredAnnotations()))) { - continue; - } - - final Type[] genericParameterTypes = constructor.getGenericParameterTypes(); - final Annotation[][] annotations = constructor.getParameterAnnotations(); - - int paramsCount = 0; - final List parameters = new ArrayList(); - for (int i = 0; i < genericParameterTypes.length; i++) { - final List tmpAnnotations = Arrays.asList(annotations[i]); - if (isContext(tmpAnnotations)) { - paramsCount++; - } else { - final Type genericParameterType = genericParameterTypes[i]; - final List tmpParameters = collectParameters(genericParameterType, tmpAnnotations); - if (tmpParameters.size() >= 1) { - for (Parameter tmpParameter : tmpParameters) { - if (ParameterProcessor - .applyAnnotations(swagger, tmpParameter, genericParameterType, tmpAnnotations) - != null) { - parameters.add(tmpParameter); - } - } - paramsCount++; - } - } - } - - if (paramsCount >= maxParamsCount) { - maxParamsCount = paramsCount; - selected = parameters; - } - } - - return selected; - } - - /** - * Collects field-level parameters from class. - * - * @param cls is a class for collecting - * @param swagger is the instance of the Swagger - * @return the collection of supported parameters - */ - public static List collectFieldParameters(Class cls, Swagger swagger) { - final List parameters = new ArrayList(); - for (Field field : ReflectionUtils.getDeclaredFields(cls)) { - final List annotations = Arrays.asList(field.getAnnotations()); - final Type genericType = field.getGenericType(); - for (Parameter parameter : collectParameters(genericType, annotations)) { - if (ParameterProcessor.applyAnnotations(swagger, parameter, genericType, annotations) != null) { - parameters.add(parameter); - } - } - } - return parameters; - } - - /** - * Splits the provided array of strings into an array, using comma as the separator. Also removes leading and - * trailing whitespace and omits empty strings from the results. - * - * @param strings is the provided array of strings - * @return the resulted array of strings - */ - public static String[] splitContentValues(String[] strings) { - final Set result = new LinkedHashSet(); - - for (String string : strings) { - Iterables.addAll(result, Splitter.on(",").trimResults().omitEmptyStrings().split(string)); - } - - return result.toArray(new String[result.size()]); - } - - private static List collectParameters(Type type, List annotations) { - final Iterator chain = SwaggerExtensions.chain(); - return chain.hasNext() ? chain.next().extractParameters(annotations, type, new HashSet(), chain) : - Collections.emptyList(); - } - - private static boolean isContext(List annotations) { - // Remove jaxrs -// for (Annotation annotation : annotations) { -// if (annotation instanceof Context) { -// return true; -// } -// } - return false; - } -} diff --git a/de-swagger-reader/src/test/java/io/swagger/sample/reader/DEWebscript.java b/de-swagger-reader/src/test/java/io/swagger/sample/reader/DEWebscript.java deleted file mode 100644 index 630e7687..00000000 --- a/de-swagger-reader/src/test/java/io/swagger/sample/reader/DEWebscript.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.swagger.sample.reader; - -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptResponse; - -@SwaggerDefinition( - info = @Info( - description = "This is the swagger specification for a TEST moehahaha", - version = "1.33.7", - title = "Swagger Dynamic Extensions Test", - //termsOfService = "http://swagger.io/terms/", - contact = @Contact(name = "XeniT", email = "apix@xenit.eu", url = "http://www.xenit.eu") - //license = @License(name = "Apache 2.0", url = "http://www.apache.org/licenses/LICENSE-2.0.html") - ), - //consumes = {"application/json", "application/xml"}, - produces = {"application/json"}, - schemes = {SwaggerDefinition.Scheme.HTTP, SwaggerDefinition.Scheme.HTTPS}, - tags = {@Tag(name = "core", description = "Core Operations")} -) -//@WebScript(description = "Webscript description", baseUri = "/de") -@RestController -public class DEWebscript { - - @GetMapping("/home") - @ApiOperation(value = "/home summary", tags = "core", notes = "/home description") - public SampleModel simpleGet(@RequestParam String requestParam, - @RequestParam(required = false) String requiredParam, - @RequestParam String pathParam, - SampleModel bodyParam) { - return new SampleModel(); - } - - @GetMapping("/ignoreParams") - public void ignoreParams(WebScriptRequest request, WebScriptResponse responose) { - - } -} diff --git a/de-swagger-reader/src/test/java/io/swagger/sample/reader/DEWebscriptSwaggerTest.java b/de-swagger-reader/src/test/java/io/swagger/sample/reader/DEWebscriptSwaggerTest.java deleted file mode 100644 index cca88d70..00000000 --- a/de-swagger-reader/src/test/java/io/swagger/sample/reader/DEWebscriptSwaggerTest.java +++ /dev/null @@ -1,111 +0,0 @@ -package io.swagger.sample.reader; - - -import com.fasterxml.jackson.core.JsonProcessingException; -import eu.xenit.swagger.reader.Reader; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Swagger; -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.parameters.PathParameter; -import io.swagger.models.parameters.QueryParameter; -import io.swagger.util.Json; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; - -import static org.junit.Assert.*; - -/** - * Created by Michiel Huygen on 02/03/2016. - */ -public class DEWebscriptSwaggerTest { - - private final static Logger logger = LoggerFactory.getLogger(DEWebscriptSwaggerTest.class); - - private Reader reader; - - @Before - public void Setup() { - reader = new Reader(new Swagger()); - reader.read(DEWebscript.class); - } - - @After - public void TearDown() throws JsonProcessingException { - String json = Json.mapper().writeValueAsString(reader.getSwagger()); - logger.debug(json); - } - - @Test - public void TestParser() throws IOException { - - String json = Json.mapper().writeValueAsString(reader.getSwagger()); - logger.debug(json); - } - - @Test - public void TestDetectWebscriptAnnotation() throws JsonProcessingException { - assertFalse(reader.getSwagger().getPaths().isEmpty()); - } - - @Test - public void TestReadUriAnnotation() throws JsonProcessingException { - Path path = reader.getSwagger().getPath("/de/home"); // Testing basepath - assertNotNull(path); - - Operation get = path.getGet(); - - assertNotNull(get); - - assertEquals("core", get.getTags().get(0)); - assertEquals("/home summary", get.getSummary()); - assertEquals("/home description", get.getDescription()); - - logger.debug(path.toString()); - } - - @Test - public void TestReadParameters() throws JsonProcessingException { - - Path path = reader.getSwagger().getPath("/de/home"); - Operation get = path.getGet(); - logger.debug(get.getParameters().toString()); - - QueryParameter p1 = (QueryParameter) get.getParameters().get(0); - QueryParameter p2 = (QueryParameter) get.getParameters().get(1); - PathParameter p3 = (PathParameter) get.getParameters().get(2); - BodyParameter p4 = (BodyParameter) get.getParameters().get(3); - assertEquals("requestParam", p1.getName()); - assertEquals("query", p1.getIn()); - assertEquals(true, p1.getRequired()); - assertEquals("string", p1.getType()); - - assertEquals("requiredParam", p2.getName()); - assertEquals(false, p2.getRequired()); - assertEquals("string", p1.getType()); - - assertEquals("pathParam", p3.getName()); - assertEquals("path", p3.getIn()); - assertEquals("string", p1.getType()); - - assertEquals("body", p4.getName()); // Is this correct - assertEquals("body", p4.getIn()); - //assertEquals("body", p4.getSchema()); - - } - - @Test - public void TestIgnoreWebscriptRequestAndResponse() throws JsonProcessingException { - - Path path = reader.getSwagger().getPath("/de/ignoreParams"); - Operation get = path.getGet(); - assertEquals(0, get.getParameters().size()); - logger.debug(get.getParameters().toString()); - } - -} diff --git a/de-swagger-reader/src/test/java/io/swagger/sample/reader/ResourceListingIT.java b/de-swagger-reader/src/test/java/io/swagger/sample/reader/ResourceListingIT.java deleted file mode 100644 index b01d8ed7..00000000 --- a/de-swagger-reader/src/test/java/io/swagger/sample/reader/ResourceListingIT.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.swagger.sample.reader; - -import io.swagger.models.Info; -import io.swagger.models.Scheme; -import io.swagger.models.Swagger; -import io.swagger.models.Tag; -import io.swagger.util.Json; - -import org.junit.Assert; -import org.junit.Test; - -import java.io.IOException; -import java.net.URL; -import java.util.Arrays; -import java.util.Collections; - -public class ResourceListingIT { - - @Test - public void readerTest() throws IOException { - final Swagger swagger = Json.mapper() - .readValue(new URL("http://localhost:8002/api/swagger.json"), Swagger.class); - - Assert.assertNotNull(swagger); - - final Info info = swagger.getInfo(); - Assert.assertNotNull(info); - Assert.assertEquals(info.getDescription(), "This is a sample server"); - Assert.assertEquals(info.getVersion(), "1.0.0"); - Assert.assertEquals(info.getTitle(), "Swagger Sample Servlet"); - - Assert.assertEquals(info.getContact().getName(), "Sponge-Bob"); - Assert.assertEquals(info.getContact().getUrl(), "http://swagger.io"); - Assert.assertEquals(info.getContact().getEmail(), "apiteam@swagger.io"); - - Assert.assertEquals(info.getLicense().getName(), "Apache 2.0"); - Assert.assertEquals(info.getLicense().getUrl(), "http://www.apache.org/licenses/LICENSE-2.0.html"); - - Assert.assertEquals(swagger.getHost(), "localhost:8002"); - Assert.assertEquals(swagger.getSwagger(), "2.0"); - - Assert.assertEquals(swagger.getTags(), - Collections.singletonList(new Tag().name("users").description("Operations about user"))); - Assert.assertEquals(swagger.getSchemes(), Arrays.asList(Scheme.HTTP, Scheme.HTTPS)); - Assert.assertEquals(swagger.getConsumes(), Arrays.asList("application/json", "application/xml")); - Assert.assertEquals(swagger.getConsumes(), Arrays.asList("application/json", "application/xml")); - - Assert.assertNotNull(swagger.getPath("/sample/users/getUser")); - Assert.assertTrue(swagger.getDefinitions().containsKey("ApiResponse")); - Assert.assertTrue(swagger.getDefinitions().containsKey("SampleData")); - } -} diff --git a/de-swagger-reader/src/test/java/io/swagger/sample/reader/SampleModel.java b/de-swagger-reader/src/test/java/io/swagger/sample/reader/SampleModel.java deleted file mode 100644 index 6fc923ca..00000000 --- a/de-swagger-reader/src/test/java/io/swagger/sample/reader/SampleModel.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.swagger.sample.reader; - -/** - * Created by Michiel Huygen on 11/03/2016. - */ -public class SampleModel { - - public String field; -} diff --git a/settings.gradle b/settings.gradle index b52413e8..fb6affdf 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,8 +2,6 @@ rootProject.name = 'apix' include ':apix-interface' include ':apix-rest-v1' -include ':swagger-doc-extractor' -include ':de-swagger-reader' include ':apix-impl' include ':apix-impl:apix-impl-62' diff --git a/swagger-doc-extractor/README.md b/swagger-doc-extractor/README.md deleted file mode 100644 index d5d1431a..00000000 --- a/swagger-doc-extractor/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Swagger Documentation Extractor -Tiny Java application that extracts the Swagger specification for -Alfred API based on its source code. - -It is only used by https://bitbucket.org/xenit/alfred-docs to build the -Swagger documentation served at https://docs.xenit.eu/alfred-api when a -version of Alfred API is released. - - -### Background -In Alfred API —contrary to the usual workflow— the Swagger spec is generated -from the source code. The spec is then served by a running Alfred API (by -using the code in `de-swagger-reader`). For the building of the documentation -however we don't want the overhead of starting up an entire Alfred API stack. - -## Usage -```bash -./gradle --quiet :swagger-doc-extractor:run -``` \ No newline at end of file diff --git a/swagger-doc-extractor/build.gradle b/swagger-doc-extractor/build.gradle deleted file mode 100644 index 5f91ffbf..00000000 --- a/swagger-doc-extractor/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -plugins { - id 'application' -} - -group = 'eu.xenit.apix.swaggerdoc' -description = 'Xenit Alfred API Swagger YAML extractor' - -ext { - // Alfresco version doesn't matter for this application - alfresco_version = alfresco_70_version -} - -dependencies { - implementation(project(':apix-impl')) - implementation group: 'org.alfresco', name: 'alfresco-repository', version: alfresco_version - implementation group: 'eu.xenit.de', name: 'annotations-runtime', version: de_version - implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.0' -} - -application { - mainClassName = "${group}.Main" -} diff --git a/swagger-doc-extractor/src/main/java/eu/xenit/apix/swaggerdoc/Main.java b/swagger-doc-extractor/src/main/java/eu/xenit/apix/swaggerdoc/Main.java deleted file mode 100644 index 017be769..00000000 --- a/swagger-doc-extractor/src/main/java/eu/xenit/apix/swaggerdoc/Main.java +++ /dev/null @@ -1,19 +0,0 @@ -package eu.xenit.apix.swaggerdoc; - -import com.fasterxml.jackson.core.JsonProcessingException; -import eu.xenit.apix.alfresco.version.VersionService; -import eu.xenit.apix.rest.v1.DocumentationWebscript; -import io.swagger.util.Json; - -public class Main { - - public static void main(String args[]) throws JsonProcessingException { - System.out.println(generateSwagger()); - } - - private static String generateSwagger() throws JsonProcessingException { - DocumentationWebscript documentationWebscript = new DocumentationWebscript(new VersionService(), null); - return Json.mapper().writeValueAsString(documentationWebscript.generateSwagger()); - } - -} From b95aa0809beb8114fbce865eec718ecfeac13c20 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Thu, 27 Oct 2022 17:22:46 +0300 Subject: [PATCH 05/90] ALFREDAPI-504 Drop obsolete classes --- .../Integration_Tests_50.xml | 28 ------------------- .../Integration_tests_51__JUnit_.xml | 21 -------------- .../Integration_tests_51__JUnit___1_.xml | 20 ------------- 3 files changed, 69 deletions(-) delete mode 100644 _idea_runConfigurations/Integration_Tests_50.xml delete mode 100644 _idea_runConfigurations/Integration_tests_51__JUnit_.xml delete mode 100644 _idea_runConfigurations/Integration_tests_51__JUnit___1_.xml diff --git a/_idea_runConfigurations/Integration_Tests_50.xml b/_idea_runConfigurations/Integration_Tests_50.xml deleted file mode 100644 index cd6b8a11..00000000 --- a/_idea_runConfigurations/Integration_Tests_50.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/_idea_runConfigurations/Integration_tests_51__JUnit_.xml b/_idea_runConfigurations/Integration_tests_51__JUnit_.xml deleted file mode 100644 index 9ea37389..00000000 --- a/_idea_runConfigurations/Integration_tests_51__JUnit_.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/_idea_runConfigurations/Integration_tests_51__JUnit___1_.xml b/_idea_runConfigurations/Integration_tests_51__JUnit___1_.xml deleted file mode 100644 index 42e55020..00000000 --- a/_idea_runConfigurations/Integration_tests_51__JUnit___1_.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - \ No newline at end of file From 2c5892122191e03379d1c8fb22045a51a07e2990 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Thu, 27 Oct 2022 18:05:51 +0300 Subject: [PATCH 06/90] ALFREDAPI-504 Commented out WIP Swagger migration from v1.5 to 3+ --- .../rest/AlfredApiRestServletContext.java | 116 +++++++++--------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java index c30bc5f5..14720054 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java @@ -13,30 +13,30 @@ import org.alfresco.rest.framework.jacksonextensions.RestJsonModule; import org.alfresco.service.namespace.NamespaceService; import org.springframework.beans.factory.InitializingBean; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration; +//import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +//import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; +//import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +//import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration; import org.springframework.context.annotation.*; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +//import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +//import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping; -import springfox.documentation.RequestHandler; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spi.service.RequestHandlerProvider; -import springfox.documentation.spring.web.WebMvcRequestHandler; -import springfox.documentation.spring.web.paths.Paths; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper; -import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider; -import springfox.documentation.spring.web.readers.operation.HandlerMethodResolver; -import springfox.documentation.swagger2.annotations.EnableSwagger2; +//import springfox.documentation.RequestHandler; +//import springfox.documentation.builders.PathSelectors; +//import springfox.documentation.builders.RequestHandlerSelectors; +//import springfox.documentation.spi.DocumentationType; +//import springfox.documentation.spi.service.RequestHandlerProvider; +//import springfox.documentation.spring.web.WebMvcRequestHandler; +//import springfox.documentation.spring.web.paths.Paths; +//import springfox.documentation.spring.web.plugins.Docket; +//import springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper; +//import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider; +//import springfox.documentation.spring.web.readers.operation.HandlerMethodResolver; +//import springfox.documentation.swagger2.annotations.EnableSwagger2; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; @@ -48,12 +48,12 @@ @Configuration @EnableWebMvc -@EnableSwagger2 -@EnableAutoConfiguration(exclude = { - DataSourceAutoConfiguration.class, - ActiveMQAutoConfiguration.class, - FreeMarkerAutoConfiguration.class -}) +//@EnableSwagger2 +//@EnableAutoConfiguration(exclude = { +// DataSourceAutoConfiguration.class, +// ActiveMQAutoConfiguration.class, +// FreeMarkerAutoConfiguration.class +//}) @PropertySource(value = { "classpath:application.properties" }) // should pick up other controllers from the same package by default @ComponentScan(basePackages = { "eu.xenit.apix" }) @@ -109,14 +109,14 @@ public boolean isMultipart(HttpServletRequest request) { return resolver; } - @Bean - public Docket api() { - return new Docket(DocumentationType.SWAGGER_2) - .select() - .paths(PathSelectors.ant("/api/**")) - .apis(RequestHandlerSelectors.basePackage("eu.xenit.apix")) - .build(); - } +// @Bean +// public Docket api() { +// return new Docket(DocumentationType.SWAGGER_2) +// .select() +// .paths(PathSelectors.ant("/api/**")) +// .apis(RequestHandlerSelectors.basePackage("eu.xenit.apix")) +// .build(); +// } // @Override // public void addResourceHandlers(ResourceHandlerRegistry registry) { @@ -146,30 +146,30 @@ public Docket api() { // ); // } - @Bean - public InitializingBean removeSpringfoxHandlerProvider(DocumentationPluginsBootstrapper bootstrapper) { - return () -> bootstrapper.getHandlerProviders().removeIf(WebMvcRequestHandlerProvider.class::isInstance); - } - - @Bean - public RequestHandlerProvider customRequestHandlerProvider(Optional servletContext, - HandlerMethodResolver methodResolver, - List handlerMappings) { - String contextPath = servletContext.map(ServletContext::getContextPath).orElse(Paths.ROOT); - return () -> handlerMappings.stream() - .filter(mapping -> !mapping.getClass().getSimpleName() - .equals("IntegrationRequestMappingHandlerMapping")) - .map(mapping -> mapping.getHandlerMethods().entrySet()) - .flatMap(Set::stream) - .map(entry -> new WebMvcRequestHandler(contextPath, methodResolver, - tweakInfo(entry.getKey()), entry.getValue())) - .sorted(RequestHandler.byPatternsCondition()) - .collect(Collectors.toList()); - } - - RequestMappingInfo tweakInfo(RequestMappingInfo info) { - if (info.getPathPatternsCondition() == null) return info; - String[] patterns = info.getPathPatternsCondition().getPatternValues().toArray(String[]::new); - return info.mutate().options(new RequestMappingInfo.BuilderConfiguration()).paths(patterns).build(); - } +// @Bean +// public InitializingBean removeSpringfoxHandlerProvider(DocumentationPluginsBootstrapper bootstrapper) { +// return () -> bootstrapper.getHandlerProviders().removeIf(WebMvcRequestHandlerProvider.class::isInstance); +// } +// +// @Bean +// public RequestHandlerProvider customRequestHandlerProvider(Optional servletContext, +// HandlerMethodResolver methodResolver, +// List handlerMappings) { +// String contextPath = servletContext.map(ServletContext::getContextPath).orElse(Paths.ROOT); +// return () -> handlerMappings.stream() +// .filter(mapping -> !mapping.getClass().getSimpleName() +// .equals("IntegrationRequestMappingHandlerMapping")) +// .map(mapping -> mapping.getHandlerMethods().entrySet()) +// .flatMap(Set::stream) +// .map(entry -> new WebMvcRequestHandler(contextPath, methodResolver, +// tweakInfo(entry.getKey()), entry.getValue())) +// .sorted(RequestHandler.byPatternsCondition()) +// .collect(Collectors.toList()); +// } +// +// RequestMappingInfo tweakInfo(RequestMappingInfo info) { +// if (info.getPathPatternsCondition() == null) return info; +// String[] patterns = info.getPathPatternsCondition().getPatternValues().toArray(String[]::new); +// return info.mutate().options(new RequestMappingInfo.BuilderConfiguration()).paths(patterns).build(); +// } } \ No newline at end of file From ad08cd38477badc8d644ef6906605e779fe0848d Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Thu, 27 Oct 2022 18:06:53 +0300 Subject: [PATCH 07/90] ALFREDAPI-504 Added temporary local dependency for Alfresco MVC until it's published for PR review --- build.gradle | 1 + temp-dependencies/alfresco-mvc-rest-8.0.0.jar | Bin 0 -> 33037 bytes 2 files changed, 1 insertion(+) create mode 100644 temp-dependencies/alfresco-mvc-rest-8.0.0.jar diff --git a/build.gradle b/build.gradle index 05913c6c..27c6ff4f 100644 --- a/build.gradle +++ b/build.gradle @@ -60,6 +60,7 @@ ext { care4alfVersion = '2.3.0' mvc = "8.0.0" +// mvc = "7.5.1-RELEASE" alfrescoVersion = "7.2.0" } diff --git a/temp-dependencies/alfresco-mvc-rest-8.0.0.jar b/temp-dependencies/alfresco-mvc-rest-8.0.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..d79d4eacefc97f70605fe0de44ad7b7e69523980 GIT binary patch literal 33037 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 Y Date: Mon, 31 Oct 2022 11:33:41 +0200 Subject: [PATCH 08/90] ALFREDAPI-504 Added exec permissions to the gradle wrapper --- gradlew | 0 gradlew.bat | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew mode change 100644 => 100755 gradlew.bat diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/gradlew.bat b/gradlew.bat old mode 100644 new mode 100755 From a476c1fcf782e243d924856489f6f0bab1c96d2d Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Mon, 31 Oct 2022 12:41:10 +0200 Subject: [PATCH 09/90] ALFREDAPI-504 Added missing transitive dependency apache commons lang from Dynamic Extensions --- apix-impl/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index dd508d6c..bddc7f04 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -90,6 +90,7 @@ allprojects { dependencies { implementation(project(":apix-interface")) + implementation 'commons-lang:commons-lang:1.0' alfrescoProvided group: 'org.alfresco', name: 'alfresco-repository', version: alfresco_version alfrescoProvided group: 'org.alfresco', name: 'alfresco-remote-api', version: alfresco_version From 902a7433598d68a3fb4e0ca7cb04d47c306e9d3c Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Mon, 31 Oct 2022 13:23:26 +0200 Subject: [PATCH 10/90] ALFREDAPI-504 Removed funky dependency from the integration test plugin --- apix-integrationtests/build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apix-integrationtests/build.gradle b/apix-integrationtests/build.gradle index 99b4d096..58568404 100644 --- a/apix-integrationtests/build.gradle +++ b/apix-integrationtests/build.gradle @@ -31,6 +31,9 @@ allprojects { implementation { extendsFrom integrationTestImplementationRemote } + integrationTestImplementationLocal { + exclude(group: 'commons-lang', module: 'commons-lang') + } } dependencies { From 49bbc213256dc98fa7ca64a3818573ec0e7365b4 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Mon, 31 Oct 2022 15:33:30 +0200 Subject: [PATCH 11/90] ALFREDAPI-504 Initial DE Commented code cleanup --- apix-docker/build.gradle | 4 +++ apix-integrationtests/build.gradle | 6 ++-- apix-interface/build.gradle | 4 +-- apix-rest-v1/build.gradle | 23 +++++---------- build.gradle | 45 ++++++------------------------ 5 files changed, 26 insertions(+), 56 deletions(-) diff --git a/apix-docker/build.gradle b/apix-docker/build.gradle index 85b0dcf1..5e330423 100644 --- a/apix-docker/build.gradle +++ b/apix-docker/build.gradle @@ -4,6 +4,10 @@ plugins { id 'be.vbgn.ci-detect' version '0.5.0' apply false } +ext { + de_version = "2.1.3" +} + subprojects { apply plugin: 'eu.xenit.docker-alfresco' apply plugin: 'eu.xenit.docker-compose' diff --git a/apix-integrationtests/build.gradle b/apix-integrationtests/build.gradle index 58568404..47c371d5 100644 --- a/apix-integrationtests/build.gradle +++ b/apix-integrationtests/build.gradle @@ -32,6 +32,8 @@ allprojects { extendsFrom integrationTestImplementationRemote } integrationTestImplementationLocal { + // Removes weird dependency lodged inside the remote testing tools + // https://github.com/xenit-eu/alfresco-remote-testrunner/blob/564df30f25dab78f6a7aad02f3ba01fcf9a38b13/alfresco-remote-testrunner-gradle-plugin/src/main/java/eu/xenit/testing/integrationtesting/gradle/internal/IntegrationTestConfigurations.java#L84 exclude(group: 'commons-lang', module: 'commons-lang') } } @@ -87,8 +89,8 @@ subprojects { } } - installBundle.enabled = false - jar.enabled = false + jar.enabled = false // empty jar + installBundle.enabled = false // no need to install an empty jar installIntegrationTestingBundle { dependsOn assembleTask diff --git a/apix-interface/build.gradle b/apix-interface/build.gradle index 75843c97..718bbfa8 100644 --- a/apix-interface/build.gradle +++ b/apix-interface/build.gradle @@ -4,12 +4,12 @@ apply from: "${rootProject.projectDir}/publish.gradle" task sourcesJar(type: Jar) { from sourceSets.main.allJava - classifier = 'sources' + archiveClassifier = 'sources' } task javadocJar(type: Jar) { from javadoc - classifier = 'javadoc' + archiveClassifier = 'javadoc' // Temporary workaround for https://bugs.openjdk.java.net/browse/JDK-8244171 javadoc.options.addBooleanOption("-no-module-directories", true) } diff --git a/apix-rest-v1/build.gradle b/apix-rest-v1/build.gradle index 2cd368e7..fe989eeb 100644 --- a/apix-rest-v1/build.gradle +++ b/apix-rest-v1/build.gradle @@ -36,12 +36,6 @@ dependencies { compileOnly project(':apix-interface') compileOnly('org.alfresco:alfresco-remote-api') - // The REST API use one call from DE annotations-runtime for the bulk endpoint - // although annotations-runtime is internal -// compileOnly(group: 'eu.xenit.de', name: 'annotations-runtime', version: de_version) { transitive = false } -// compileOnly(group: 'eu.xenit.de', name: 'annotations', version: de_version) { transitive = false } -// compileOnly(group: 'eu.xenit.de', name: 'webscripts', version: de_version) { transitive = false } - compileOnly "com.gradecak.alfresco-mvc:alfresco-mvc-rest:$mvc" compileOnly "javax.servlet:javax.servlet-api:4.0.1" @@ -53,16 +47,13 @@ dependencies { // implementation "com.fasterxml.jackson.datatype:jackson-datatype-joda" implementation group: 'io.swagger', name: 'swagger-annotations', version: swagger_version - testImplementation 'org.springframework:spring-core:3.2.10.RELEASE' - testImplementation 'org.springframework:spring-test:3.2.10.RELEASE' -// testImplementation group: 'org.springframework.extensions.surf', name: 'spring-webscripts', version: alfrescoVersion - testImplementation "org.alfresco.surf:spring-webscripts" - testImplementation group: 'org.mockito', name: 'mockito-core', version: '2.25.1' -// testImplementation group: 'eu.xenit.de', name: 'annotations', version: de_version -// testImplementation group: 'eu.xenit.de', name: 'annotations-runtime', version: de_version -// testImplementation group: 'eu.xenit.de', name: 'webscripts', version: de_version - testImplementation (group: 'org.alfresco', name: 'alfresco-repository', version: '7.2.0') - testImplementation (group: 'org.alfresco', name: 'alfresco-remote-api', version: '7.2.0') testImplementation project(':apix-interface') testImplementation project(':apix-impl') + testImplementation platform("org.alfresco:acs-community-packaging:$alfrescoVersion") + testImplementation 'org.springframework:spring-core' + testImplementation 'org.springframework:spring-test' + testImplementation "org.alfresco.surf:spring-webscripts" + testImplementation 'org.alfresco:alfresco-repository' + testImplementation 'org.alfresco:alfresco-remote-api' + testImplementation group: 'org.mockito', name: 'mockito-core', version: '2.25.1' } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 27c6ff4f..7e127bd2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,36 +1,9 @@ -//def bundleClassPath(configuration) { -// def list = ['.'] -// configuration.each { -// list += 'lib/' + it.name -// } -// return list.join(',') -//} -// -//def includeResource(configuration) { -// def list = [] -// configuration.each { -// //We have to replace the backslashes with forward slashes because on windows the path will just be unseparated. -// //For example when you have path "C\:Users\Someone\.gradle\caches" it will become "C\:UsersSomeone.gradlecaches" -// def normalizedPath = it.path.replace("\\", "/") -// list += 'lib/' + it.name + "=" + normalizedPath -// } -// return list.join(',') -//} -// -//def getVersionQualifier(String branch_name) { -// if(branch_name.startsWith('release')) -// return '' -// //Osgi in 5x accepts - in qualifier, 6x does not. Suggest removing branch section from snapshot qualifiers all together. -// return '.SNAPSHOT' -//} - -buildscript { - repositories { - mavenCentral() - maven { - url "https://maven.alfresco.com/nexus/content/groups/public" - } - } +def static getVersionQualifier(String branch_name) { + if(branch_name.startsWith('release')) + return '' + // Osgi in 5x accepts - in qualifier, 6x does not. + // Suggest removing branch section from snapshot qualifiers all together. + return '.SNAPSHOT' } ext { @@ -38,11 +11,11 @@ ext { jackson_version = '2.8.3' swagger_version = "1.5.7" // 2.2.4 - de_version = "3.0.0" http_core_version = "4.3.3" http_version = "4.3.4" + alfresco_61_version = "6.1" alfresco_62_version = "6.2" alfresco_70_version = "7.0" alfresco_71_version = "7.1" @@ -51,6 +24,7 @@ ext { // alfresco-data-model might have a different version number than the main war it's included in // ref: https://bitbucket.org/xenit/alfresco-bom/src/master/repo/eu/xenit/alfresco/ for the bom of vanilla alfresco + alfresco_61_dm_version = "8.25.1" alfresco_62_dm_version = "8.50.18" alfresco_70_dm_version = "8.424" alfresco_71_dm_version = "12.23" @@ -60,7 +34,6 @@ ext { care4alfVersion = '2.3.0' mvc = "8.0.0" -// mvc = "7.5.1-RELEASE" alfrescoVersion = "7.2.0" } @@ -68,7 +41,7 @@ subprojects { apply plugin: 'java' group = 'eu.xenit.apix' - version = "4.0" // versionWithoutQualifier + getVersionQualifier(System.env.BRANCH_NAME ?: 'local') + version = versionWithoutQualifier + getVersionQualifier(System.env.BRANCH_NAME ?: 'local') sourceCompatibility = 11 targetCompatibility = 11 From 04bc1307bd8f1dc35b5289b3dddb07defa0520fc Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Mon, 31 Oct 2022 15:40:46 +0200 Subject: [PATCH 12/90] ALFREDAPI-504 REST API cleanup of DE Commented code --- .../staging/workflow/WorkflowWebscript.java | 1 - .../xenit/apix/rest/v1/GeneralWebscript.java | 2 - .../apix/rest/v1/bulk/BulkWebscript1.java | 5 -- .../v1/categories/CategoryWebScript1.java | 2 - .../ConfigurationWebscript1.java | 2 - .../v1/dictionary/DictionaryWebScript1.java | 2 - .../v1/internal/ApixArgumentResolver.java | 48 ------------------- .../apix/rest/v1/nodes/NodesWebscript1.java | 2 - .../apix/rest/v1/people/PeopleWebscript1.java | 2 - .../v1/properties/PropertiesWebScript1.java | 8 ---- .../apix/rest/v1/search/SearchWebScript1.java | 2 - .../apix/rest/v1/sites/SitesWebscript1.java | 2 - .../apix/rest/v1/temp/LogsWebscript.java | 2 - .../xenit/apix/rest/v1/temp/WIPWebscript.java | 2 - .../translation/TranslationsWebscript1.java | 5 -- .../VersionHistoryWebScript1.java | 5 -- .../WorkingcopiesWebscript1.java | 5 -- .../apix/rest/v2/groups/GroupsWebscript.java | 5 -- 18 files changed, 102 deletions(-) delete mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/internal/ApixArgumentResolver.java diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java index acfbd067..b78868b1 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java @@ -1,6 +1,5 @@ package eu.xenit.apix.rest.staging.workflow; -import com.fasterxml.jackson.databind.JsonNode; import eu.xenit.apix.search.SearchQueryResult; import eu.xenit.apix.workflow.IWorkflowService; import eu.xenit.apix.workflow.model.Task; diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java index 943eb352..df552f49 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java @@ -9,8 +9,6 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -//@WebScript(baseUri = RestV1Config.BaseUrl, families = {RestV1Config.Family}, defaultFormat = "json", -// description = "General API operations", value = "General") //@Authentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.GeneralWebscript") public class GeneralWebscript extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java index 79af9ff8..fba65980 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java @@ -27,11 +27,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -/** - * Created by kenneth on 18.03.16. Largely rewritten by roel on 13.03.18 - */ -//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", -// description = "Perform multiple operations in a single call", value = "Bulk") @RestController("eu.xenit.apix.rest.v1.BulkWebscript") public class BulkWebscript1 extends ApixV1Webscript { private static final Logger logger = LoggerFactory.getLogger(BulkWebscript1.class); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java index 06bd79bb..2bc467a9 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java @@ -13,8 +13,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -//@WebScript(baseUri = RestV1Config.BaseUrl + "/category", families = RestV1Config.Family, defaultFormat = "json", -// description = "Retrieves Category information", value = "Category") //@Authentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.categories.CategoryWebScript1") public class CategoryWebScript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java index f64bea26..eb1ab7a7 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java @@ -26,8 +26,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", -// description = "Retrieves configuration data files from the datadictionary", value = "Configuration") //@Authentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.configuration.ConfigurationWebscript1") public class ConfigurationWebscript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java index fce351df..073a039e 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java @@ -23,8 +23,6 @@ import javax.servlet.http.HttpServletRequest; -//@WebScript(baseUri = RestV1Config.BaseUrl + "/dictionary", families = RestV1Config.Family, defaultFormat = "json", -// description = "Retrieves Dictionary information", value = "Dictionary") //@Authentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.property.DictionaryWebScript1") public class DictionaryWebScript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/internal/ApixArgumentResolver.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/internal/ApixArgumentResolver.java deleted file mode 100644 index 6e777336..00000000 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/internal/ApixArgumentResolver.java +++ /dev/null @@ -1,48 +0,0 @@ -// TODO @Zlatin FIXME Alfresco MVC to be tested - -//package eu.xenit.apix.rest.v1.internal; -// -//import com.fasterxml.jackson.databind.ObjectMapper; -//import java.io.IOException; -//import java.lang.annotation.Annotation; -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -//import org.springframework.extensions.webscripts.WebScriptRequest; -//import org.springframework.extensions.webscripts.WebScriptResponse; -//import org.springframework.stereotype.Component; -// -///** -// * Created by Michiel Huygen on 14/03/2016. -// */ -//@Component -//public class ApixArgumentResolver implements ArgumentResolver { -// -// private Logger logger = LoggerFactory.getLogger(ApixArgumentResolver.class); -// -// @Override -// public final boolean supports(final Class parameterType, final Class annotationType) { -// /* Determine if using Class.isAssignableFrom() breaks backwards compatibility. */ -// return parameterType.getCanonicalName().startsWith("eu.xenit.apix") && !Exception.class.isAssignableFrom(parameterType); -// } -// -// @Override -// public final Object resolveArgument(final Class argumentType, final Annotation parameterAnnotation, -// final String name, final WebScriptRequest request, final WebScriptResponse response) { -// /*final Class expectedParameterType = getExpectedArgumentType(); -// if (argumentType.equals(expectedParameterType) == false) { -// throw new IllegalArgumentException(String.format("Incorrect parameter type %s, expected type %s", -// argumentType, expectedParameterType)); -// }*/ -// -// try { -// //TODO: inject apix object mapper? -// ObjectMapper map = new ObjectMapper(); -// return map.readValue(request.getContent().getContent(), argumentType); -// } catch (IOException e) { -// logger.warn("Cannot convert webscript argument with type from package eu.xenit.apix to json", e); -// throw new RuntimeException("Cannot convert webscript argument (" + name + ") " + -// "with type from package eu.xenit.apix to json - " + argumentType.getCanonicalName(), e); -// } -// } -// -//} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java index 74b61040..3c3af6f8 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java @@ -53,8 +53,6 @@ import org.springframework.web.multipart.MultipartFile; -//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", -// description = "Access operations on nodes", value = "Nodes") //@Transaction(readOnly = false) @RestController("eu.xenit.apix.rest.v1.NodesWebscript") public class NodesWebscript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java index 4bd34453..14a9afad 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java @@ -15,8 +15,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", -// description = "Retrieves person information", value = "People") //@Authentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.people.PeopleWebscript") public class PeopleWebscript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java index c554ff90..8721d5ed 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java @@ -14,12 +14,8 @@ import org.springframework.web.bind.annotation.RestController; /** - * Created by Jasperhilven on 13-Jan-17. - * * @deprecated Use DictionaryWebScript1 instead */ -//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", -// description = "Retrieves Property information", value = "Properties") //@Authentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.property.PropertiesWebScript1") public class PropertiesWebScript1 extends ApixV1Webscript { @@ -37,10 +33,6 @@ public PropertiesWebScript1(IPropertyService propertyService) { //https://stackoverflow.com/questions/13482020/encoded-slash-2f-with-spring-requestmapping-path-param-gives-http-400 public ResponseEntity getPropertyDefinition(@PathVariable final QName qname, @RequestParam(required = false) QName qnameWithSlash) { -// String qnameUsed = qnameWithSlash != null ? qnameWithSlash : qname; -// String decoded = java.net.URLDecoder.decode(qnameUsed, "UTF-8"); -// logger.debug("Asked versionhistory for node with guid: {}", decoded); -// eu.xenit.apix.data.QName apixQName = new eu.xenit.apix.data.QName(qnameUsed); // TODO @Zlatin FIXME Alfresco MVC some crappy URL shenanigans ? Unit-tested? QName apixQName = qnameWithSlash != null ? qnameWithSlash : qname; PropertyDefinition propDef = propertyService.GetPropertyDefinition(apixQName); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java index ce01c28d..d1653965 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java @@ -14,8 +14,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", -// description = "Perform search queries", value = "Search") //@Authentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.search.SearchWebScriptV1") public class SearchWebScript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java index e9215a11..bcab8869 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java @@ -22,8 +22,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", -// description = "Access operations on sites", value = "Sites") //@Transaction(readOnly = false) @RestController("eu.xenit.apix.rest.v1.SitesWebscript") public class SitesWebscript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java index a6223c41..819ec16d 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java @@ -12,8 +12,6 @@ import org.springframework.web.bind.annotation.RestController; -//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", -// description = "Display logs") @Api(hidden = true) @RestController("eu.xenit.apix.rest.v1.temp.LogsWebscript") public class LogsWebscript extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java index 63a5ad7c..972b5380 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java @@ -14,8 +14,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", -// description = "Work In Progress - UNSTABLE", value = "WIP") @RestController("eu.xenit.apix.rest.v1.temp.WIPWebscript") public class WIPWebscript extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java index ef2279bd..d78f5d00 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java @@ -12,11 +12,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -/** - * Created by Stan on 30-Mar-16. - */ -//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", -// description = "Retrieve translations", value = "Translations") @RestController("eu.xenit.apix.rest.v1.translation.TranslationsWebscript1") public class TranslationsWebscript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java index d235fbc3..5e22e884 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java @@ -24,11 +24,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -/** - * Created by stan on 5/2/16. - */ -//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", -// description = "Retrieves version history information", value = "VersionHistory") //@Authentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.versionhistory.VersionHistoryWebScript1") public class VersionHistoryWebScript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java index 51ac81a7..6af0e2ab 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java @@ -15,11 +15,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -/** - * Created by Michiel Huygen on 09/03/2016. - */ -//@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json", -// description = "Access operations on working copies", value = "Workingcopies") @RestController("eu.xenit.apix.rest.v1.WorkingcopiesWebscript1") public class WorkingcopiesWebscript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java index 08f975e9..0a4831bc 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java @@ -21,12 +21,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -/** - * Created by jasper on 14/03/17. - */ -//@WebScript(baseUri = RestV2Config.BaseUrl, families = RestV2Config.Family, defaultFormat = "json", -// description = "Retrieves group information and links users/groups to parent groups", value = "Groups") //@Authentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v2.groups.GroupsWebscript") public class GroupsWebscript extends ApixV2Webscript { From 3f6c9247b32b03a8e2a5da455cc00feb7e29dbbe Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Mon, 31 Oct 2022 15:59:42 +0200 Subject: [PATCH 13/90] ALFREDAPI-504 Enabled Alfresco MVC AOP for Authentication and Transaction management --- apix-docker/build.gradle | 1 + apix-rest-v1/build.gradle | 11 ++++++----- .../eu/xenit/apix/rest/v1/GeneralWebscript.java | 4 +++- .../rest/v1/categories/CategoryWebScript1.java | 4 +++- .../configuration/ConfigurationWebscript1.java | 4 +++- .../v1/dictionary/DictionaryWebScript1.java | 4 +++- .../apix/rest/v1/nodes/NodesWebscript1.java | 7 ++----- .../apix/rest/v1/people/PeopleWebscript1.java | 4 +++- .../v1/properties/PropertiesWebScript1.java | 4 +++- .../apix/rest/v1/search/SearchWebScript1.java | 4 +++- .../apix/rest/v1/sites/SitesWebscript1.java | 3 ++- .../VersionHistoryWebScript1.java | 4 +++- .../apix/rest/v2/groups/GroupsWebscript.java | 6 ++++-- .../apix/rest/v2/nodes/NodesWebscriptV2.java | 7 ++----- .../apix/rest/v2/people/PeopleWebscript.java | 6 +++--- temp-dependencies/alfresco-mvc-aop-8.0.0.jar | Bin 0 -> 18696 bytes 16 files changed, 44 insertions(+), 29 deletions(-) create mode 100644 temp-dependencies/alfresco-mvc-aop-8.0.0.jar diff --git a/apix-docker/build.gradle b/apix-docker/build.gradle index 5e330423..8239aa6d 100644 --- a/apix-docker/build.gradle +++ b/apix-docker/build.gradle @@ -26,6 +26,7 @@ subprojects { alfrescoAmp project(path: ':apix-integrationtests-model-amp', configuration: 'ampArchives') alfrescoAmp project(path: ':apix-rest-v1', configuration: 'ampArtifact') alfrescoSM "com.gradecak.alfresco-mvc:alfresco-mvc-rest:$mvc" + alfrescoSM "com.gradecak.alfresco-mvc:alfresco-mvc-aop:$mvc" alfrescoSM files(jar) alfrescoAmp "eu.xenit:alfresco-dynamic-extensions-repo-${subproject_alfresco_version}:${de_version}@amp" } diff --git a/apix-rest-v1/build.gradle b/apix-rest-v1/build.gradle index fe989eeb..39d5ea0c 100644 --- a/apix-rest-v1/build.gradle +++ b/apix-rest-v1/build.gradle @@ -32,12 +32,13 @@ dependencies { //// implementation "io.springfox:springfox-spring-integration-webmvc:3.0.0" // Alfresco dependency should be removed in the future - compileOnly("org.alfresco:alfresco-repository") - compileOnly project(':apix-interface') - compileOnly('org.alfresco:alfresco-remote-api') + alfrescoProvided("org.alfresco:alfresco-repository") + alfrescoProvided project(':apix-interface') + alfrescoProvided('org.alfresco:alfresco-remote-api') - compileOnly "com.gradecak.alfresco-mvc:alfresco-mvc-rest:$mvc" - compileOnly "javax.servlet:javax.servlet-api:4.0.1" + alfrescoProvided "com.gradecak.alfresco-mvc:alfresco-mvc-rest:$mvc" + alfrescoProvided "com.gradecak.alfresco-mvc:alfresco-mvc-aop:$mvc" + alfrescoProvided "javax.servlet:javax.servlet-api:4.0.1" // compile(project(':de-swagger-reader')) diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java index df552f49..790720bf 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java @@ -1,5 +1,7 @@ package eu.xenit.apix.rest.v1; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.version.IVersionService; import eu.xenit.apix.version.VersionDescription; import io.swagger.annotations.ApiOperation; @@ -9,7 +11,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -//@Authentication(AuthenticationType.USER) +@AlfrescoAuthentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.GeneralWebscript") public class GeneralWebscript extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java index 2bc467a9..55f5f8d4 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java @@ -1,5 +1,7 @@ package eu.xenit.apix.rest.v1.categories; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.categories.Category; import eu.xenit.apix.categories.ICategoryService; import eu.xenit.apix.data.QName; @@ -13,7 +15,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -//@Authentication(AuthenticationType.USER) +@AlfrescoAuthentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.categories.CategoryWebScript1") public class CategoryWebScript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java index eb1ab7a7..b85a7be0 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java @@ -3,6 +3,8 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.ObjectMapper; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.configuration.ConfigurationFileFlags; import eu.xenit.apix.configuration.ConfigurationService; import eu.xenit.apix.configuration.Configurations; @@ -26,7 +28,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -//@Authentication(AuthenticationType.USER) +@AlfrescoAuthentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.configuration.ConfigurationWebscript1") public class ConfigurationWebscript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java index 073a039e..4bf748f7 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java @@ -1,5 +1,7 @@ package eu.xenit.apix.rest.v1.dictionary; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.data.QName; import eu.xenit.apix.dictionary.IDictionaryService; import eu.xenit.apix.dictionary.aspects.AspectDefinition; @@ -23,7 +25,7 @@ import javax.servlet.http.HttpServletRequest; -//@Authentication(AuthenticationType.USER) +@AlfrescoAuthentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.property.DictionaryWebScript1") public class DictionaryWebScript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java index 3c3af6f8..55a2f8f4 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java @@ -1,7 +1,6 @@ package eu.xenit.apix.rest.v1.nodes; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.comments.Comment; import eu.xenit.apix.comments.Conversation; import eu.xenit.apix.comments.ICommentService; @@ -46,14 +45,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.InputStreamResource; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.servlet.FormData; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -//@Transaction(readOnly = false) +@AlfrescoTransaction @RestController("eu.xenit.apix.rest.v1.NodesWebscript") public class NodesWebscript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java index 14a9afad..65927350 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java @@ -1,5 +1,7 @@ package eu.xenit.apix.rest.v1.people; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.people.IPeopleService; import eu.xenit.apix.people.Person; import eu.xenit.apix.rest.v1.ApixV1Webscript; @@ -15,7 +17,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -//@Authentication(AuthenticationType.USER) +@AlfrescoAuthentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.people.PeopleWebscript") public class PeopleWebscript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java index 8721d5ed..6383c854 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java @@ -1,5 +1,7 @@ package eu.xenit.apix.rest.v1.properties; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.data.QName; import eu.xenit.apix.dictionary.properties.IPropertyService; import eu.xenit.apix.properties.PropertyDefinition; @@ -16,7 +18,7 @@ /** * @deprecated Use DictionaryWebScript1 instead */ -//@Authentication(AuthenticationType.USER) +@AlfrescoAuthentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.property.PropertiesWebScript1") public class PropertiesWebScript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java index d1653965..2bf6b19d 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java @@ -1,5 +1,7 @@ package eu.xenit.apix.rest.v1.search; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.rest.v1.ApixV1Webscript; import eu.xenit.apix.search.ISearchService; import eu.xenit.apix.search.SearchQuery; @@ -14,7 +16,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -//@Authentication(AuthenticationType.USER) +@AlfrescoAuthentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.search.SearchWebScriptV1") public class SearchWebScript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java index bcab8869..63137484 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java @@ -1,5 +1,6 @@ package eu.xenit.apix.rest.v1.sites; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.filefolder.IFileFolderService; import eu.xenit.apix.node.INodeService; @@ -22,7 +23,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -//@Transaction(readOnly = false) +@AlfrescoTransaction @RestController("eu.xenit.apix.rest.v1.SitesWebscript") public class SitesWebscript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java index 5e22e884..d6f72bb0 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java @@ -1,5 +1,7 @@ package eu.xenit.apix.rest.v1.versionhistory; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.data.QName; import eu.xenit.apix.rest.v1.ApixV1Webscript; import eu.xenit.apix.versionhistory.IVersionHistoryService; @@ -24,7 +26,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -//@Authentication(AuthenticationType.USER) +@AlfrescoAuthentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.versionhistory.VersionHistoryWebScript1") public class VersionHistoryWebScript1 extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java index 0a4831bc..c923bb95 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java @@ -1,5 +1,7 @@ package eu.xenit.apix.rest.v2.groups; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.groups.Group; import eu.xenit.apix.people.IPeopleService; import eu.xenit.apix.people.Person; @@ -22,11 +24,11 @@ import org.springframework.web.bind.annotation.RestController; -//@Authentication(AuthenticationType.USER) +@AlfrescoAuthentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v2.groups.GroupsWebscript") public class GroupsWebscript extends ApixV2Webscript { - Logger logger = LoggerFactory.getLogger(GroupsWebscript.class); + private static final Logger logger = LoggerFactory.getLogger(GroupsWebscript.class); private final IPeopleService personService; public GroupsWebscript(IPeopleService personService) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java index b5e29366..ad1171c8 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java @@ -1,5 +1,6 @@ package eu.xenit.apix.rest.v2.nodes; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.data.QName; import eu.xenit.apix.filefolder.IFileFolderService; @@ -31,11 +32,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -//@WebScript(baseUri = RestV2Config.BaseUrl, families = RestV2Config.Family, defaultFormat = "json", -// description = "Access operations on nodes", value = "Nodes") -//@Transaction( -// readOnly = false -//) +@AlfrescoAuthentication @RestController("eu.xenit.apix.rest.v2.NodesWebscript") public class NodesWebscriptV2 extends ApixV2Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java index c5394740..78aea183 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java @@ -1,5 +1,7 @@ package eu.xenit.apix.rest.v2.people; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.people.IPeopleService; import eu.xenit.apix.people.Person; import eu.xenit.apix.rest.v2.ApixV2Webscript; @@ -17,9 +19,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -//@WebScript(baseUri = RestV2Config.BaseUrl, families = RestV2Config.Family, defaultFormat = "json", -// description = "Retrieves person information", value = "People") -//@Authentication(AuthenticationType.USER) +@AlfrescoAuthentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v2.people.PeopleWebscript") public class PeopleWebscript extends ApixV2Webscript { diff --git a/temp-dependencies/alfresco-mvc-aop-8.0.0.jar b/temp-dependencies/alfresco-mvc-aop-8.0.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..820ee76998e1b214461f27ed1e2e9179fc2bbddd GIT binary patch literal 18696 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%0A+^k#^NSuZfN0|%XI5;*gj{tXX>}s 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 Lr2*gB?g0M}P?9DP literal 0 HcmV?d00001 From 5d7496ff8c508ee02fd39b15fc4d4465dbc92ea1 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Mon, 31 Oct 2022 17:08:28 +0200 Subject: [PATCH 14/90] ALFREDAPI-504 Further code cleanup; Updated commented Authentication annotations from DE to Alfresco MVC; Improved Gradle dependency configuration for apix-impl transitive dependencies; Cleanup of apix-integrationtests build.gradle --- apix-docker/62/docker-compose.yml | 14 +++- apix-docker/70/docker-compose.yml | 26 ++++--- apix-docker/71/docker-compose.yml | 26 ++++--- apix-docker/72/docker-compose.yml | 12 +-- apix-impl/build.gradle | 75 +++++-------------- apix-impl/config/log4j.properties | 2 +- .../ConfigurationServiceImpl.java | 2 +- apix-integrationtests/61/overrides.gradle | 0 apix-integrationtests/62/overrides.gradle | 13 +--- apix-integrationtests/70/overrides.gradle | 13 +--- apix-integrationtests/71/overrides.gradle | 13 +--- apix-integrationtests/72/overrides.gradle | 13 +--- apix-integrationtests/build.gradle | 26 +++++-- apix-integrationtests/overrides.gradle | 19 +---- .../apix/rest/v1/tests/CopyNodeTest.java | 32 ++++---- .../apix/rest/v1/tests/CreateNodeTest.java | 13 ++-- .../apix/rest/v1/tests/NodeContentTest.java | 6 +- .../apix/rest/v1/tests/NodesBaseTest.java | 4 +- .../ClassificationGetWebscript.java | 2 +- .../DictionaryServiceChecksumWebscript.java | 2 +- .../v0/metadata/MetadataBulkWebscript.java | 2 +- .../v0/metadata/MetadataGetWebscript.java | 2 +- .../apix/rest/v0/search/SearchWebScript0.java | 2 +- .../ConfigurationWebscript1.java | 14 ---- .../apix/rest/v1/nodes/CreateNodeOptions.java | 3 +- .../apix/rest/v1/temp/LogsWebscript.java | 5 +- .../src/main/resources/log4j.properties | 2 +- .../xenit/apix/rest/NodesWebscript1Test.java | 2 - ...tDEWebscript1.java => TestWebscript1.java} | 12 ++- 29 files changed, 136 insertions(+), 221 deletions(-) create mode 100644 apix-integrationtests/61/overrides.gradle rename apix-rest-v1/src/test/java/eu/xenit/apix/rest/{TestDEWebscript1.java => TestWebscript1.java} (58%) diff --git a/apix-docker/62/docker-compose.yml b/apix-docker/62/docker-compose.yml index dcc44fa3..f290947b 100644 --- a/apix-docker/62/docker-compose.yml +++ b/apix-docker/62/docker-compose.yml @@ -11,6 +11,14 @@ services: environment: - SOLR_HOST=solr - TERM=xterm + ## Needed for Solr indexing + - GLOBAL_local.transform.service.enabled=true + # Disable transformations and renditions + - GLOBAL_contentPropertyRestrictions.enabled=false + - GLOBAL_ooo.enabled=false + - GLOBAL_jodconverter.enabled=false + - GLOBAL_transform.service.enabled=false + - GLOBAL_legacy.transform.service.enabled=false solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 @@ -28,9 +36,9 @@ services: - POSTGRES_DB=alfresco restart: unless-stopped - jodconverter: - image: hub.xenit.eu/public/jodconverter-ws - restart: unless-stopped +# jodconverter: +# image: hub.xenit.eu/public/jodconverter-ws +# restart: unless-stopped volumes: alfresco: diff --git a/apix-docker/70/docker-compose.yml b/apix-docker/70/docker-compose.yml index 1c7a4894..b5b9f8ff 100644 --- a/apix-docker/70/docker-compose.yml +++ b/apix-docker/70/docker-compose.yml @@ -13,6 +13,14 @@ services: - TERM=xterm - GLOBAL_messaging.broker.url=failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true - GLOBAL_localTransform.core-aio.url=http://transform-core-aio:8090/ + ## Needed for Solr indexing + - GLOBAL_local.transform.service.enabled=true + # Disable transformations and renditions + - GLOBAL_contentPropertyRestrictions.enabled=false + - GLOBAL_ooo.enabled=false + - GLOBAL_jodconverter.enabled=false + - GLOBAL_transform.service.enabled=false + - GLOBAL_legacy.transform.service.enabled=false solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 @@ -32,15 +40,15 @@ services: - POSTGRES_DB=alfresco restart: unless-stopped - activemq: - image: alfresco/alfresco-activemq:5.16.1 - mem_limit: 1g - - transform-core-aio: - image: alfresco/alfresco-transform-core-aio:2.5.0 - environment: - JAVA_OPTS: " -Xms256m -Xmx512m" - ACTIVEMQ_URL: "nio://activemq:61616" +# activemq: +# image: alfresco/alfresco-activemq:5.16.1 +# mem_limit: 1g +# +# transform-core-aio: +# image: alfresco/alfresco-transform-core-aio:2.5.0 +# environment: +# JAVA_OPTS: " -Xms256m -Xmx512m" +# ACTIVEMQ_URL: "nio://activemq:61616" volumes: alfresco: diff --git a/apix-docker/71/docker-compose.yml b/apix-docker/71/docker-compose.yml index 1c7a4894..b5b9f8ff 100644 --- a/apix-docker/71/docker-compose.yml +++ b/apix-docker/71/docker-compose.yml @@ -13,6 +13,14 @@ services: - TERM=xterm - GLOBAL_messaging.broker.url=failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true - GLOBAL_localTransform.core-aio.url=http://transform-core-aio:8090/ + ## Needed for Solr indexing + - GLOBAL_local.transform.service.enabled=true + # Disable transformations and renditions + - GLOBAL_contentPropertyRestrictions.enabled=false + - GLOBAL_ooo.enabled=false + - GLOBAL_jodconverter.enabled=false + - GLOBAL_transform.service.enabled=false + - GLOBAL_legacy.transform.service.enabled=false solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 @@ -32,15 +40,15 @@ services: - POSTGRES_DB=alfresco restart: unless-stopped - activemq: - image: alfresco/alfresco-activemq:5.16.1 - mem_limit: 1g - - transform-core-aio: - image: alfresco/alfresco-transform-core-aio:2.5.0 - environment: - JAVA_OPTS: " -Xms256m -Xmx512m" - ACTIVEMQ_URL: "nio://activemq:61616" +# activemq: +# image: alfresco/alfresco-activemq:5.16.1 +# mem_limit: 1g +# +# transform-core-aio: +# image: alfresco/alfresco-transform-core-aio:2.5.0 +# environment: +# JAVA_OPTS: " -Xms256m -Xmx512m" +# ACTIVEMQ_URL: "nio://activemq:61616" volumes: alfresco: diff --git a/apix-docker/72/docker-compose.yml b/apix-docker/72/docker-compose.yml index 67607fab..ace92124 100644 --- a/apix-docker/72/docker-compose.yml +++ b/apix-docker/72/docker-compose.yml @@ -15,12 +15,12 @@ services: - GLOBAL_localTransform.core-aio.url=http://transform-core-aio:8090/ ## Needed for Solr indexing - GLOBAL_local.transform.service.enabled=true -# # Disable transformations and renditions -# - GLOBAL_contentPropertyRestrictions.enabled=false -# - GLOBAL_ooo.enabled=false -# - GLOBAL_jodconverter.enabled=false -# - GLOBAL_transform.service.enabled=false -# - GLOBAL_legacy.transform.service.enabled=false + # Disable transformations and renditions + - GLOBAL_contentPropertyRestrictions.enabled=false + - GLOBAL_ooo.enabled=false + - GLOBAL_jodconverter.enabled=false + - GLOBAL_transform.service.enabled=false + - GLOBAL_legacy.transform.service.enabled=false solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index bddc7f04..c3bb497e 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -18,17 +18,18 @@ subprojects { apply from: "${project.projectDir}/overrides.gradle" apply from: "${rootProject.projectDir}/publish.gradle" apply plugin: 'eu.xenit.amp' + apply plugin: 'java-library' configurations { ampArtifact -// dynamicExtensionsBundles + } + + artifacts { + ampArtifact amp } dependencies { - implementation(project(":apix-impl")) -// dynamicExtensionsBundles(group: 'eu.xenit.swagger.ui', name: 'swagger-ui_5x', version: '1.1.0') { -// transitive = false -// } // Works for 6x too + api(project(":apix-impl")) } publishing { @@ -40,17 +41,12 @@ subprojects { } } - artifacts { - ampArtifact amp - } - sourceSets { main { java { srcDirs = ['src/main/java', '../src/main/java'] } amp { -// dynamicExtension() module("src/main/config/module.properties") } } @@ -64,9 +60,8 @@ subprojects { // Extend amp plugin task: // We want to add 'alfresco-global.properties' etc to the module-specific folder in the AMP - // (e.g. 'config/module/alfresco/module/apix-impl-51/') without hard-coding project name for each Alfresco version. + // (e.g. 'config/module/alfresco/module/apix-impl-72/') without hard-coding project name for each Alfresco version. amp { -// deBundles = configurations.dynamicExtensionsBundles + files(jar) into("config/alfresco/module/${project.name}") { from("${project.parent.projectDir}/config/alfresco-global.properties") from("${project.parent.projectDir}/config/log4j.properties") @@ -85,25 +80,25 @@ subprojects { allprojects { // allprojects also applies to shared code (under apix-impl/src) that needs to work in IntelliJ -// apply plugin: 'eu.xenit.de' apply plugin: 'eu.xenit.alfresco' + apply plugin: 'java-library' dependencies { - implementation(project(":apix-interface")) + api(project(":apix-interface")) implementation 'commons-lang:commons-lang:1.0' - alfrescoProvided group: 'org.alfresco', name: 'alfresco-repository', version: alfresco_version - alfrescoProvided group: 'org.alfresco', name: 'alfresco-remote-api', version: alfresco_version + + alfrescoProvided platform("org.alfresco:acs-community-packaging:$alfrescoVersion") + alfrescoProvided("org.alfresco:alfresco-repository") + alfrescoProvided('org.alfresco:alfresco-remote-api') implementation group: 'org.yaml', name: 'snakeyaml', version: '1.15' implementation group: 'javax.validation', name: 'validation-api', version: '1.1.0.Final' -// testCompile group: 'eu.xenit.de', name: 'annotations', version: de_version - testImplementation group: 'org.alfresco', name: 'alfresco-repository', version: alfresco_repo_version - testImplementation group: 'org.alfresco', name: 'alfresco-data-model', version: alfresco_dm_version - testImplementation group: 'org.alfresco', name: 'alfresco-remote-api', version: alfresco_version - + testImplementation platform("org.alfresco:acs-community-packaging:$alfrescoVersion") + testImplementation 'org.alfresco:alfresco-repository' + testImplementation 'org.alfresco:alfresco-remote-api' + testImplementation 'org.alfresco:alfresco-data-model' testImplementation group: 'org.mockito', name: 'mockito-core', version: '2.25.1' - testImplementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.2' testImplementation group: 'eu.xenit.testing', name: 'integration-testing', version: '1.1.0' } @@ -132,40 +127,4 @@ public class Version { // Show test results when running from the CLI testLogging { events "PASSED", "FAILED", "SKIPPED" } } - -// jar { -// // This BundleSymbolicName is also used in -// // apix-impl/src/integration-test/java/eu/xenit/apix/tests/ApixImplBundleFilter.java -// // to find which integration tests need to run, so when changing it, change it there too. -// bnd( -// 'Export-Package': 'eu.xenit.apix.*; -split-package:=merge-first', -// 'Include-Resource': includeResource(configurations.compile), -// 'Bundle-ClassPath': bundleClassPath(configurations.compile), -// 'Bundle-SymbolicName': "${project.group}.${project.name}", -// 'Bundle-Description': 'Alfred API: Java API and REST API', -// 'Import-Package': 'org.springframework.beans.factory,' -// + 'org.springframework.cglib.core,' -// + 'org.springframework.cglib.proxy,' -// // Unintuitively, the notation 'version="1.0"' means any version >= 1.0 -// + 'org.json;version="1.0",' -// // Alfresco >=7.3 uses a SLF4J version >2.0, so we need to override the default upper boundary of 2.0. -// + 'org.slf4j.*;version="1.7",' -// + '!com.google.appengine.api,' -// + '!com.google.apphosting.api,' -// + '!org.joda.convert,' -// + '*' -// ) -// } - -// alfrescoDynamicExtensions { -// versions.dynamicExtensions = de_version -// // Configure endpoint for installBundle task -// repository { -// endpoint { -// protocol = project.hasProperty('protocol') ? project.protocol : 'http' -// host = project.hasProperty('host') ? project.host : 'localhost' -// port = project.hasProperty('port') ? project.port : 8080 -// } -// } -// } } diff --git a/apix-impl/config/log4j.properties b/apix-impl/config/log4j.properties index dde52fb9..8ba427c5 100644 --- a/apix-impl/config/log4j.properties +++ b/apix-impl/config/log4j.properties @@ -1 +1 @@ -log4j.logger.eu.xenit.apix = INFO + log4j.logger.eu.xenit.apix = INFO diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java index 9bc25c6d..051a86b8 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java @@ -38,7 +38,7 @@ public class ConfigurationServiceImpl implements ConfigurationService { private static final String QNAME_FOLDER = TYPE_FOLDER.toString(); private static final QName QNAME_NAME = new QName(PROP_NAME.toString()); - Logger logger = LoggerFactory.getLogger(ConfigurationServiceImpl.class); + private static final Logger logger = LoggerFactory.getLogger(ConfigurationServiceImpl.class); @Autowired IFileFolderService fileFolderService; diff --git a/apix-integrationtests/61/overrides.gradle b/apix-integrationtests/61/overrides.gradle new file mode 100644 index 00000000..e69de29b diff --git a/apix-integrationtests/62/overrides.gradle b/apix-integrationtests/62/overrides.gradle index 2f5c71ca..a770658c 100644 --- a/apix-integrationtests/62/overrides.gradle +++ b/apix-integrationtests/62/overrides.gradle @@ -1,14 +1,3 @@ ext { - subproject_alfresco_version = "62" - alfresco_version = alfresco_62_version - alfresco_dm_version = alfresco_62_dm_version - alfresco_repo_version = '7.134.1' - alfresco_remote_api_version = '7.107.1' -} - -dependencies { - integrationTestImplementationRemote(group: 'org.apache.httpcomponents', name: 'fluent-hc', version: http_version) { - exclude group: 'commons-logging' - exclude group: 'org.apache.httpcomponents', module: 'httpcore' - } + alfresco_version = "6.2.0-ga" } \ No newline at end of file diff --git a/apix-integrationtests/70/overrides.gradle b/apix-integrationtests/70/overrides.gradle index 0a41d118..be985b0d 100644 --- a/apix-integrationtests/70/overrides.gradle +++ b/apix-integrationtests/70/overrides.gradle @@ -1,14 +1,3 @@ ext { - subproject_alfresco_version = "70" - alfresco_version = alfresco_70_version - alfresco_dm_version = alfresco_70_dm_version - alfresco_repo_version = '8.424' - alfresco_remote_api_version = '8.424' -} - -dependencies { - integrationTestImplementationRemote(group: 'org.apache.httpcomponents', name: 'fluent-hc', version: http_version) { - exclude group: 'commons-logging' - exclude group: 'org.apache.httpcomponents', module: 'httpcore' - } + alfresco_version = "7.0.0" } \ No newline at end of file diff --git a/apix-integrationtests/71/overrides.gradle b/apix-integrationtests/71/overrides.gradle index 9e6eeb47..1f5276eb 100644 --- a/apix-integrationtests/71/overrides.gradle +++ b/apix-integrationtests/71/overrides.gradle @@ -1,14 +1,3 @@ ext { - subproject_alfresco_version = "71" - alfresco_version = alfresco_71_version - alfresco_dm_version = alfresco_71_dm_version - alfresco_repo_version = '12.23' - alfresco_remote_api_version = '12.23' -} - -dependencies { - integrationTestImplementationRemote(group: 'org.apache.httpcomponents', name: 'fluent-hc', version: http_version) { - exclude group: 'commons-logging' - exclude group: 'org.apache.httpcomponents', module: 'httpcore' - } + alfresco_version = "7.1.1" } \ No newline at end of file diff --git a/apix-integrationtests/72/overrides.gradle b/apix-integrationtests/72/overrides.gradle index c454125d..f34112bd 100644 --- a/apix-integrationtests/72/overrides.gradle +++ b/apix-integrationtests/72/overrides.gradle @@ -1,14 +1,3 @@ ext { - subproject_alfresco_version = "72" - alfresco_version = alfresco_72_version - alfresco_dm_version = alfresco_72_dm_version - alfresco_repo_version = '14.142' - alfresco_remote_api_version = '14.142' -} - -dependencies { - integrationTestImplementationRemote(group: 'org.apache.httpcomponents', name: 'fluent-hc', version: http_version) { - exclude group: 'commons-logging' - exclude group: 'org.apache.httpcomponents', module: 'httpcore' - } + alfresco_version = "7.2.1" } \ No newline at end of file diff --git a/apix-integrationtests/build.gradle b/apix-integrationtests/build.gradle index 47c371d5..32a92871 100644 --- a/apix-integrationtests/build.gradle +++ b/apix-integrationtests/build.gradle @@ -38,21 +38,30 @@ allprojects { } } + // Subproject of supported Alfresco version 61/62/70/71/72 + def implVersion = project.projectDir.name == "apix-integrationtests" + ? "61" // minimum supported version + : project.projectDir.name dependencies { alfrescoProvided project(":apix-rest-v1") alfrescoProvided project(":apix-interface") - alfrescoProvided project(":apix-impl") // Needed because of the below transitive exclusion // Add services used to the integration test fatjar, since we can't access the ones deployed in Alfresco - integrationTestImplementationRemote (project(":apix-impl:apix-impl-${subproject_alfresco_version}")) { + integrationTestImplementationRemote (project(":apix-impl:apix-impl-$implVersion")) { // Already includes apix-interface, we need to exclude it to avoid Linkage errors from // having 2 of the same classes on the classpath // (1 in Alfresco from apix-impl AMP + 1 in DE from the integration tests fat jar) - transitive = false + exclude(group: "eu.xenit.apix", module: "apix-interface") } - alfrescoProvided group: 'org.alfresco', name: 'alfresco-repository', version: alfresco_repo_version - alfrescoProvided group: 'org.alfresco', name: 'alfresco-remote-api', version: alfresco_remote_api_version - alfrescoProvided group: 'org.alfresco', name: 'alfresco-data-model', version: alfresco_dm_version + integrationTestImplementationRemote("org.apache.httpcomponents:fluent-hc:$http_version") { + exclude group: 'commons-logging' + exclude group: 'org.apache.httpcomponents', module: 'httpcore' + } + + alfrescoProvided platform("org.alfresco:acs-community-packaging:$alfrescoVersion") + alfrescoProvided("org.alfresco:alfresco-repository") + alfrescoProvided('org.alfresco:alfresco-remote-api') + alfrescoProvided('org.alfresco:alfresco-data-model') alfrescoProvided group: 'org.osgi', name: 'org.osgi.core', version: '4.3.1' // Below is a temporary fix to circumvent using commons-lang 1.0.0 JAR. This jar @@ -67,8 +76,9 @@ allprojects { } subprojects { - def projectApixImpl = project(":apix-impl:apix-impl-${subproject_alfresco_version}") - def projectDocker = project(":apix-docker:docker-${subproject_alfresco_version}") + // Subproject of supported Alfresco version 61/62/70/71/72 + def projectApixImpl = project(":apix-impl:apix-impl-${project.projectDir.name}") + def projectDocker = project(":apix-docker:docker-${project.projectDir.name}") evaluationDependsOn(projectApixImpl.path) evaluationDependsOn(projectDocker.path) def assembleTask = projectApixImpl.tasks.getByName("assemble") diff --git a/apix-integrationtests/overrides.gradle b/apix-integrationtests/overrides.gradle index 0ce595d8..5b4f4530 100644 --- a/apix-integrationtests/overrides.gradle +++ b/apix-integrationtests/overrides.gradle @@ -1,16 +1,3 @@ - -// This is a duplicate of the ./72/overrides.gradle to make code navigation work in shared code -ext { - subproject_alfresco_version = "72" - alfresco_version = alfresco_72_version - alfresco_dm_version = alfresco_72_dm_version - alfresco_repo_version = '14.142' - alfresco_remote_api_version = '14.142' -} - -dependencies { - integrationTestImplementationRemote(group: 'org.apache.httpcomponents', name: 'fluent-hc', version: http_version) { - exclude group: 'commons-logging' - exclude group: 'org.apache.httpcomponents', module: 'httpcore' - } -} \ No newline at end of file +// This is a duplicate of the ./61/overrides.gradle to make code navigation work in shared code +// minimum supported Alfresco version 6.1 +apply from: "$project.projectDir/61/overrides.gradle" \ No newline at end of file diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java index 77ad1bfd..868b563b 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java @@ -6,7 +6,6 @@ import eu.xenit.apix.node.INodeService; import eu.xenit.apix.rest.v1.nodes.CreateNodeOptions; -import java.io.IOException; import java.util.HashMap; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -15,16 +14,12 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; public class CopyNodeTest extends NodesBaseTest { - private final static Logger logger = LoggerFactory.getLogger(CopyNodeTest.class); private NodeRef mainTestFolder; - private NodeRef parentTestFolder; private NodeRef copyFromFile; private NodeRef copyFromFolder; @@ -43,13 +38,12 @@ public void setup() { AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); final HashMap initializedNodeRefs = init(); mainTestFolder = c.apix(getMainTestFolder()); - parentTestFolder = initializedNodeRefs.get(RestV1BaseTest.TESTFOLDER_NAME); copyFromFile = initializedNodeRefs.get(RestV1BaseTest.TESTFILE_NAME); copyFromFolder = initializedNodeRefs.get(RestV1BaseTest.TESTFOLDER_NAME); } @Test - public void testCopyFileNode() throws IOException { + public void testCopyFileNode() { CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, null, null, null , copyFromFile); NodeRef newRef = transactionService.getRetryingTransactionHelper() @@ -60,7 +54,7 @@ public void testCopyFileNode() throws IOException { } @Test - public void testCopyFileNodeWithAspectsToRemove() throws IOException { + public void testCopyFileNodeWithAspectsToRemove() { transactionService.getRetryingTransactionHelper() .doInTransaction(() -> { serviceRegistry.getNodeService().addAspect(c.alfresco(copyFromFile), ContentModel.ASPECT_TEMPORARY, new HashMap<>()); @@ -80,7 +74,7 @@ public void testCopyFileNodeWithAspectsToRemove() throws IOException { } @Test - public void testCopyFolderNode() throws IOException { + public void testCopyFolderNode() { CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, null, null, null , copyFromFolder); NodeRef newRef = transactionService.getRetryingTransactionHelper() @@ -91,7 +85,7 @@ public void testCopyFolderNode() throws IOException { } @Test - public void testCopyFileWithName() throws IOException { + public void testCopyFileWithName() { final String newName = "Copy"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, newName, null, null, copyFromFile); @@ -103,7 +97,7 @@ public void testCopyFileWithName() throws IOException { } @Test - public void testCopyFolderWithName() throws IOException { + public void testCopyFolderWithName() { final String newName = "CopiedFolder"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, newName, null, null, copyFromFolder); @@ -115,7 +109,7 @@ public void testCopyFolderWithName() throws IOException { } @Test - public void testCopyFileDuplicateName() throws IOException { + public void testCopyFileDuplicateName() { final String duplicateName = "duplicateName"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, duplicateName, null, null, copyFromFile); @@ -136,7 +130,7 @@ public void testCopyFileDuplicateName() throws IOException { } @Test - public void testCopyFolderDuplicateName() throws IOException { + public void testCopyFolderDuplicateName() { final NodeRef childRef = nodeService.getChildAssociations(mainTestFolder).get(0).getTarget(); final String newName = nodeService.getMetadata(childRef).properties.get(c.apix(ContentModel.PROP_NAME)).get(0); CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, newName, @@ -149,7 +143,7 @@ public void testCopyFolderDuplicateName() throws IOException { } @Test - public void testCopyNodeWithProperties() throws IOException { + public void testCopyNodeWithProperties() { final String newName = "NewName"; HashMap properties = getBasicProperties(); CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, newName, @@ -162,7 +156,7 @@ public void testCopyNodeWithProperties() throws IOException { } @Test - public void testCopyNodeReturnsAccesDenied() throws IOException { + public void testCopyNodeReturnsAccesDenied() { CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, null, null, null, copyFromFile); transactionService.getRetryingTransactionHelper() @@ -174,7 +168,7 @@ public void testCopyNodeReturnsAccesDenied() throws IOException { } @Test - public void testCopyFolderInception() throws IOException { + public void testCopyFolderInception() { CreateNodeOptions createNodeOptions = getCreateNodeOptions(copyFromFolder, null, null, null, copyFromFolder); transactionService.getRetryingTransactionHelper() @@ -185,7 +179,7 @@ public void testCopyFolderInception() throws IOException { } @Test - public void testCopyFolderTypeChange() throws IOException { + public void testCopyFolderTypeChange() { CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, null, c.apix(ContentModel.TYPE_CONTENT), null, copyFromFolder); transactionService.getRetryingTransactionHelper() @@ -196,7 +190,7 @@ public void testCopyFolderTypeChange() throws IOException { } @Test - public void testCopyFolderSubTyping() throws IOException { + public void testCopyFolderSubTyping() { CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, null, c.apix(ContentModel.TYPE_DICTIONARY_MODEL), null, copyFromFile); transactionService.getRetryingTransactionHelper() @@ -207,7 +201,7 @@ public void testCopyFolderSubTyping() throws IOException { } @Test - public void testMultipleCopies() throws IOException { + public void testMultipleCopies() { CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, null, null, null, copyFromFolder); for (int i = 0 ; i < 5 ; i++) { diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java index 63e60544..e7b7dd74 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java @@ -4,7 +4,6 @@ import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.data.QName; -import java.io.IOException; import java.util.HashMap; import eu.xenit.apix.rest.v1.nodes.CreateNodeOptions; import org.alfresco.model.ContentModel; @@ -39,7 +38,7 @@ public void setup() { } @Test - public void testCreateFile() throws IOException { + public void testCreateFile() { String name = "newFile"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(parentTestFolder, name, c.apix(ContentModel.TYPE_CONTENT), null, null); @@ -51,7 +50,7 @@ public void testCreateFile() throws IOException { } @Test - public void testCreateFolder() throws IOException { + public void testCreateFolder() { String name = "newFolder"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(parentTestFolder, name, c.apix(ContentModel.TYPE_FOLDER), null, null); @@ -63,7 +62,7 @@ public void testCreateFolder() throws IOException { } @Ignore - public void testCreateFileWithNoType() throws IOException { + public void testCreateFileWithNoType() { String name = "noType"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(parentTestFolder, name, null, null, null); @@ -76,7 +75,7 @@ public void testCreateFileWithNoType() throws IOException { } @Test - public void testCreateFileWithProperties() throws IOException { + public void testCreateFileWithProperties() { String name = "newFile1"; HashMap properties = getBasicProperties(); CreateNodeOptions createNodeOptions = getCreateNodeOptions(parentTestFolder, name, @@ -89,7 +88,7 @@ public void testCreateFileWithProperties() throws IOException { } @Test - public void testCreateFileDuplicateName() throws IOException { + public void testCreateFileDuplicateName() { String name = "duplicate"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(parentTestFolder, name, c.apix(ContentModel.TYPE_CONTENT), null, null); @@ -105,7 +104,7 @@ public void testCreateFileDuplicateName() throws IOException { } @Test - public void testCreateNodeReturnsAccessDenied() throws IOException { + public void testCreateNodeReturnsAccessDenied() { String name = "Forbidden"; CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, name, c.apix(ContentModel.TYPE_CONTENT), null, null); diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java index 3a4f92de..849ed101 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java @@ -7,7 +7,11 @@ import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.node.INodeService; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; import java.nio.charset.Charset; import java.util.HashMap; import org.alfresco.repo.security.authentication.AuthenticationUtil; diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java index 4d0b2c0a..26a35d41 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java @@ -88,7 +88,7 @@ public eu.xenit.apix.data.NodeRef doPostNodes(CreateNodeOptions createNodeOption protected CreateNodeOptions getCreateNodeOptions(eu.xenit.apix.data.NodeRef parentRef, String name, eu.xenit.apix.data.QName type, HashMap properties, QName[] aspectsToAdd, - QName[] aspectsToRemove, eu.xenit.apix.data.NodeRef copyFrom) throws IOException { + QName[] aspectsToRemove, eu.xenit.apix.data.NodeRef copyFrom) { String parentRefString = (parentRef != null) ? parentRef.toString() : null; String copyFromString = (copyFrom != null) ? copyFrom.toString() : null; String typeString = (type != null) ? type.toString() : null; @@ -98,7 +98,7 @@ protected CreateNodeOptions getCreateNodeOptions(eu.xenit.apix.data.NodeRef pare protected CreateNodeOptions getCreateNodeOptions(eu.xenit.apix.data.NodeRef parentRef, String name, eu.xenit.apix.data.QName type, HashMap properties, - eu.xenit.apix.data.NodeRef copyFrom) throws IOException { + eu.xenit.apix.data.NodeRef copyFrom) { return getCreateNodeOptions(parentRef, name, type, properties, null, null, copyFrom); } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/categories/ClassificationGetWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/categories/ClassificationGetWebscript.java index e0259601..67b42397 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/categories/ClassificationGetWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/categories/ClassificationGetWebscript.java @@ -21,7 +21,7 @@ public ClassificationGetWebscript(ICategoryService catService) { } @GetMapping( - value = "/v0/classification/{aspectQName}", + value = "/classification/{aspectQName}", produces = MediaType.APPLICATION_JSON_VALUE ) public ResponseEntity> execute(@PathVariable final QName aspectQName) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/dictionary/DictionaryServiceChecksumWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/dictionary/DictionaryServiceChecksumWebscript.java index 060f4fc2..e30cbae0 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/dictionary/DictionaryServiceChecksumWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/dictionary/DictionaryServiceChecksumWebscript.java @@ -19,7 +19,7 @@ public DictionaryServiceChecksumWebscript(IDictionaryService service) { } @GetMapping( - value = "/v0/dictionary/checksum", + value = "/dictionary/checksum", produces = MediaType.APPLICATION_JSON_VALUE ) public ResponseEntity> execute() { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataBulkWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataBulkWebscript.java index db647924..48b0e762 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataBulkWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataBulkWebscript.java @@ -24,7 +24,7 @@ public MetadataBulkWebscript(INodeService service, IPermissionService permission } @PostMapping( - value = "/v0/eu/xenit/metadata/bulk", + value = "/eu/xenit/metadata/bulk", produces = MediaType.APPLICATION_JSON_VALUE ) public ResponseEntity> execute(@RequestBody final List nodeRefs) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataGetWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataGetWebscript.java index 1fa2abee..f7493635 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataGetWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataGetWebscript.java @@ -20,7 +20,7 @@ public MetadataGetWebscript(INodeService service, IPermissionService permissionS } @GetMapping( - value = "/v0/eu/xenit/metadata", + value = "/eu/xenit/metadata", produces = MediaType.APPLICATION_JSON_VALUE ) public ResponseEntity execute(@RequestParam final NodeRef nodeRef) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchWebScript0.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchWebScript0.java index c7db1897..7bb1ab91 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchWebScript0.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchWebScript0.java @@ -20,7 +20,7 @@ public SearchWebScript0(ISearchService service) { } @PostMapping( - value = "/v0/eu/xenit/search", + value = "/eu/xenit/search", produces = MediaType.APPLICATION_JSON_VALUE ) public ResponseEntity execute(@RequestBody final SearchQueryV0 query){ diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java index b85a7be0..efeed318 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java @@ -77,20 +77,6 @@ public ResponseEntity getJsConfigurationFiles( .body( String.format("%s(%s)", callback, mapper.writeValueAsString(configurations))); -// webScriptResponse.setContentEncoding("utf-8"); -// webScriptResponse.setHeader("Cache-Control", "no-cache"); -// -// if (webScriptRequest.getFormat().equalsIgnoreCase("js")) { -// webScriptResponse.setContentType("application/js"); -// try(Writer writer = webScriptResponse.getWriter()) { -// writer.write(callback); -// writer.write("("); -// mapper.writeValue(writer, configurations); -// writer.write(");"); -// writer.flush(); -// } -// return; -// } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java index ec0e66da..080b1f2d 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java @@ -5,7 +5,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import eu.xenit.apix.data.QName; import io.swagger.annotations.ApiModelProperty; -import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.alfresco.model.ContentModel; @@ -34,7 +33,7 @@ public CreateNodeOptions(@JsonProperty("parent") String parent, @JsonProperty("properties") Map properties, @JsonProperty("aspectsToAdd") QName[] aspectsToAdd, @JsonProperty("aspectsToRemove") QName[] aspectsToRemove, - @JsonProperty("copyFrom") String copyFrom) throws IOException { + @JsonProperty("copyFrom") String copyFrom) { this.parent = parent; this.name = name; this.type = type; diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java index 819ec16d..33997573 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java @@ -1,5 +1,7 @@ package eu.xenit.apix.rest.v1.temp; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.rest.v1.ApixV1Webscript; import io.swagger.annotations.Api; import java.io.File; @@ -23,8 +25,7 @@ public LogsWebscript(Environment env) { } @GetMapping(value = "/v1/tmp/log", produces = { MediaType.TEXT_PLAIN_VALUE }) -// @Authentication(AuthenticationType.ADMIN) - // TODO @Zlatin FIXME Alfresco MVC user permissions --> Admin! + @AlfrescoAuthentication(AuthenticationType.ADMIN) public ResponseEntity showLog(@RequestParam(defaultValue = "200") int lines) throws IOException { StringBuilder log = new StringBuilder(); File logFile = new File(logPath); diff --git a/apix-rest-v1/src/main/resources/log4j.properties b/apix-rest-v1/src/main/resources/log4j.properties index 74996e6b..7fa621cb 100644 --- a/apix-rest-v1/src/main/resources/log4j.properties +++ b/apix-rest-v1/src/main/resources/log4j.properties @@ -6,4 +6,4 @@ log4j.appender.stdout.threshold=TRACE #log4j.logger.org.springframework.osgi=DEBUG #log4j.logger.org.springframework=DEBUG -log4j.logger.org.springframework.web.servlet.mvc.support=DEBUG \ No newline at end of file +#log4j.logger.org.springframework.web.servlet.mvc.support=DEBUG \ No newline at end of file diff --git a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/NodesWebscript1Test.java b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/NodesWebscript1Test.java index eec8cace..c9a55d1b 100644 --- a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/NodesWebscript1Test.java +++ b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/NodesWebscript1Test.java @@ -14,9 +14,7 @@ import java.io.IOException; import java.io.InputStream; -import org.springframework.extensions.webscripts.servlet.FormData; import org.junit.Test; -import org.springframework.extensions.webscripts.servlet.FormData.FormField; import org.springframework.web.multipart.MultipartFile; public class NodesWebscript1Test { diff --git a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/TestDEWebscript1.java b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/TestWebscript1.java similarity index 58% rename from apix-rest-v1/src/test/java/eu/xenit/apix/rest/TestDEWebscript1.java rename to apix-rest-v1/src/test/java/eu/xenit/apix/rest/TestWebscript1.java index 90f85fbd..ef91fea3 100644 --- a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/TestDEWebscript1.java +++ b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/TestWebscript1.java @@ -1,23 +1,21 @@ package eu.xenit.apix.rest; +import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; -/** - * Created by Michiel Huygen on 29/03/2016. - */ @RestController -//@WebScript(baseUri = "/base", families = "My Family", value = "TestDEWebscript") -//@Authentication(AuthenticationType.GUEST) -public class TestDEWebscript1 { +@AlfrescoAuthentication(AuthenticationType.GUEST) +public class TestWebscript1 { @GetMapping("/method") public void testGet() { } -// @Authentication(AuthenticationType.ADMIN) + @AlfrescoAuthentication(AuthenticationType.ADMIN) @PostMapping(value = "/method/{param}") public void testPost() { From f4f1a169c3933b31b6997e6aec8d897c39a65248 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Mon, 31 Oct 2022 20:09:30 +0200 Subject: [PATCH 15/90] ALFREDAPI-504 Fixed broken integration tests; Cleaned up Solr testing utils and multiple sourcedirs for the integration tests; Code cleanup --- apix-impl/build.gradle | 1 - apix-impl/config/log4j.properties | 2 +- .../xenit/apix/util/SolrTestHelperImpl.java | 22 ---------------- .../xenit/apix/util/SolrTestHelperImpl.java | 18 ------------- .../xenit/apix/util/SolrTestHelperImpl.java | 18 ------------- .../xenit/apix/util/SolrTestHelperImpl.java | 18 ------------- apix-integrationtests/build.gradle | 25 ++++++++----------- apix-integrationtests/overrides.gradle | 3 --- .../java/eu/xenit/apix/tests/BaseTest.java | 12 ++++----- .../v1/properties/PropertiesWebScript1.java | 3 ++- 10 files changed, 19 insertions(+), 103 deletions(-) delete mode 100644 apix-integrationtests/62/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java delete mode 100644 apix-integrationtests/70/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java delete mode 100644 apix-integrationtests/71/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java delete mode 100644 apix-integrationtests/72/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java delete mode 100644 apix-integrationtests/overrides.gradle diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index c3bb497e..79eedf40 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -99,7 +99,6 @@ allprojects { testImplementation 'org.alfresco:alfresco-remote-api' testImplementation 'org.alfresco:alfresco-data-model' testImplementation group: 'org.mockito', name: 'mockito-core', version: '2.25.1' - testImplementation group: 'eu.xenit.testing', name: 'integration-testing', version: '1.1.0' } task generateVersionFile(type: Task) { diff --git a/apix-impl/config/log4j.properties b/apix-impl/config/log4j.properties index 8ba427c5..dde52fb9 100644 --- a/apix-impl/config/log4j.properties +++ b/apix-impl/config/log4j.properties @@ -1 +1 @@ - log4j.logger.eu.xenit.apix = INFO +log4j.logger.eu.xenit.apix = INFO diff --git a/apix-integrationtests/62/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java b/apix-integrationtests/62/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java deleted file mode 100644 index b39f9643..00000000 --- a/apix-integrationtests/62/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java +++ /dev/null @@ -1,22 +0,0 @@ -package eu.xenit.apix.util; - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import javax.sql.DataSource; -import org.alfresco.repo.management.subsystems.SwitchableApplicationContextFactory; -import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class should only be used by the integration tests. - */ -public class SolrTestHelperImpl extends SolrTestHelperBaseImpl { - private Logger logger = LoggerFactory.getLogger(SolrTestHelperImpl.class); - - public SolrTestHelperImpl(String baseUrl, DataSource dataSource, SwitchableApplicationContextFactory searchSubSystem) { - super(baseUrl, dataSource, searchSubSystem); - } -} diff --git a/apix-integrationtests/70/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java b/apix-integrationtests/70/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java deleted file mode 100644 index f622da0d..00000000 --- a/apix-integrationtests/70/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package eu.xenit.apix.util; - -import javax.sql.DataSource; -import org.alfresco.repo.management.subsystems.SwitchableApplicationContextFactory; -import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class should only be used by the integration tests. - */ -public class SolrTestHelperImpl extends SolrTestHelperBaseImpl { - private Logger logger = LoggerFactory.getLogger(SolrTestHelperImpl.class); - - public SolrTestHelperImpl(String baseUrl, DataSource dataSource, SwitchableApplicationContextFactory searchSubSystem) { - super(baseUrl, dataSource, searchSubSystem); - } -} diff --git a/apix-integrationtests/71/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java b/apix-integrationtests/71/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java deleted file mode 100644 index f622da0d..00000000 --- a/apix-integrationtests/71/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package eu.xenit.apix.util; - -import javax.sql.DataSource; -import org.alfresco.repo.management.subsystems.SwitchableApplicationContextFactory; -import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class should only be used by the integration tests. - */ -public class SolrTestHelperImpl extends SolrTestHelperBaseImpl { - private Logger logger = LoggerFactory.getLogger(SolrTestHelperImpl.class); - - public SolrTestHelperImpl(String baseUrl, DataSource dataSource, SwitchableApplicationContextFactory searchSubSystem) { - super(baseUrl, dataSource, searchSubSystem); - } -} diff --git a/apix-integrationtests/72/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java b/apix-integrationtests/72/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java deleted file mode 100644 index f622da0d..00000000 --- a/apix-integrationtests/72/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package eu.xenit.apix.util; - -import javax.sql.DataSource; -import org.alfresco.repo.management.subsystems.SwitchableApplicationContextFactory; -import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class should only be used by the integration tests. - */ -public class SolrTestHelperImpl extends SolrTestHelperBaseImpl { - private Logger logger = LoggerFactory.getLogger(SolrTestHelperImpl.class); - - public SolrTestHelperImpl(String baseUrl, DataSource dataSource, SwitchableApplicationContextFactory searchSubSystem) { - super(baseUrl, dataSource, searchSubSystem); - } -} diff --git a/apix-integrationtests/build.gradle b/apix-integrationtests/build.gradle index 32a92871..76fd8266 100644 --- a/apix-integrationtests/build.gradle +++ b/apix-integrationtests/build.gradle @@ -7,29 +7,28 @@ plugins { def integrationTestsProjectDir = project.projectDir allprojects { + // Subproject of supported Alfresco version 61/62/70/71/72 + def subproject_alfresco_version = project.projectDir.name == "apix-integrationtests" + ? "61" // minimum supported version + : project.projectDir.name + // Following needs to apply to shared (./src) project and version-specific (e.g. ./70) projects. apply plugin: 'idea' apply plugin: 'eu.xenit.de' apply plugin: 'eu.xenit.alfresco-remote-testrunner' apply plugin: 'eu.xenit.alfresco' - apply from: "${project.projectDir}/overrides.gradle" + apply from: "$integrationTestsProjectDir/$subproject_alfresco_version/overrides.gradle" sourceSets { main.java.srcDirs = [] main.resources.srcDirs = [] - integrationTest.java.srcDirs = [ - "$integrationTestsProjectDir/src/main/java", - "$integrationTestsProjectDir/$subproject_alfresco_version/src/main/java" - ] - integrationTest.resources.srcDirs = [ - "$integrationTestsProjectDir/src/main/resources", - "$integrationTestsProjectDir/$subproject_alfresco_version/src/main/resources" - ] + integrationTest.java.srcDirs = ["$integrationTestsProjectDir/src/main/java"] + integrationTest.resources.srcDirs = ["$integrationTestsProjectDir/src/main/resources"] } configurations { implementation { - extendsFrom integrationTestImplementationRemote + extendsFrom integrationTestImplementation } integrationTestImplementationLocal { // Removes weird dependency lodged inside the remote testing tools @@ -38,15 +37,11 @@ allprojects { } } - // Subproject of supported Alfresco version 61/62/70/71/72 - def implVersion = project.projectDir.name == "apix-integrationtests" - ? "61" // minimum supported version - : project.projectDir.name dependencies { alfrescoProvided project(":apix-rest-v1") alfrescoProvided project(":apix-interface") // Add services used to the integration test fatjar, since we can't access the ones deployed in Alfresco - integrationTestImplementationRemote (project(":apix-impl:apix-impl-$implVersion")) { + integrationTestImplementationRemote (project(":apix-impl:apix-impl-$subproject_alfresco_version")) { // Already includes apix-interface, we need to exclude it to avoid Linkage errors from // having 2 of the same classes on the classpath // (1 in Alfresco from apix-impl AMP + 1 in DE from the integration tests fat jar) diff --git a/apix-integrationtests/overrides.gradle b/apix-integrationtests/overrides.gradle deleted file mode 100644 index 5b4f4530..00000000 --- a/apix-integrationtests/overrides.gradle +++ /dev/null @@ -1,3 +0,0 @@ -// This is a duplicate of the ./61/overrides.gradle to make code navigation work in shared code -// minimum supported Alfresco version 6.1 -apply from: "$project.projectDir/61/overrides.gradle" \ No newline at end of file diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/BaseTest.java b/apix-integrationtests/src/main/java/eu/xenit/apix/tests/BaseTest.java index f419b204..10ac6c26 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/BaseTest.java +++ b/apix-integrationtests/src/main/java/eu/xenit/apix/tests/BaseTest.java @@ -34,14 +34,14 @@ public abstract class BaseTest implements InitializingBean { //Apix Test model contstants - public final static String APIX_TESTCM_NAMESPACE = "http://test.apix.xenit.eu/model/content"; - public final static String APIX_TESTCM_PREFIX = "apixtest"; - public final static String APIX_TESTCM_PROP_SEARCHSERVICELIMITTEST_SHORTNAME = "searchServiceLimitTestProperty"; - public final static String APIX_TESTCM_PROP_SEARCHSERVICELIMITTEST_PREFIXED = + public static final String APIX_TESTCM_NAMESPACE = "http://test.apix.xenit.eu/model/content"; + public static final String APIX_TESTCM_PREFIX = "apixtest"; + public static final String APIX_TESTCM_PROP_SEARCHSERVICELIMITTEST_SHORTNAME = "searchServiceLimitTestProperty"; + public static final String APIX_TESTCM_PROP_SEARCHSERVICELIMITTEST_PREFIXED = APIX_TESTCM_PREFIX + ":" + APIX_TESTCM_PROP_SEARCHSERVICELIMITTEST_SHORTNAME; - private final static Logger logger = LoggerFactory.getLogger(BaseTest.class); - private final static String mainTestFolderName = "ApixMainTestFolder"; + private static final Logger logger = LoggerFactory.getLogger(BaseTest.class); + private static final String mainTestFolderName = "ApixMainTestFolder"; @Autowired protected ApixToAlfrescoConversion c; diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java index 6383c854..f39fcffa 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java @@ -16,10 +16,11 @@ import org.springframework.web.bind.annotation.RestController; /** - * @deprecated Use DictionaryWebScript1 instead + * @deprecated since Oct 2015, use DictionaryWebScript1 instead */ @AlfrescoAuthentication(AuthenticationType.USER) @RestController("eu.xenit.apix.rest.v1.property.PropertiesWebScript1") +@Deprecated(since = "Deprecated since Oct 2015, use DictionaryWebScript1 instead") public class PropertiesWebScript1 extends ApixV1Webscript { private final IPropertyService propertyService; From 07a472961f71857fb9f966241d09d57f55779f9f Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Mon, 31 Oct 2022 20:28:28 +0200 Subject: [PATCH 16/90] ALFREDAPI-504 Updated changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c503d08c..55b92653 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Alfred API - Changelog +## 4.0.0 (yyyy-mm-dd) + +### Added + +### Changed +* [ALFREDAPI-504](https://xenitsupport.jira.com/browse/ALFREDAPI-504): Refactored Alfred API from Dynamic Extensions to Alfresco MVC to reduce maintenance efforts and improve the integration with Spring + + +### Fixed + +### Removed + ## 4.0.1 (unreleased) From d4a5fba93f60086725d774f527af64d2820cb27d Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Mon, 31 Oct 2022 21:42:53 +0200 Subject: [PATCH 17/90] ALFREDAPI-504 Refactored all projects to avoid source path shenanigans and improve Alfresco version compatibility; Improve Solr Helper implementation; Centralized Alfresco version overrides --- alfresco/61/overrides.gradle | 5 + alfresco/62/overrides.gradle | 5 + alfresco/70/overrides.gradle | 5 + alfresco/71/overrides.gradle | 5 + alfresco/72/overrides.gradle | 7 + apix-docker/62/docker-compose.yml | 17 +- apix-docker/70/docker-compose.yml | 13 -- apix-docker/71/docker-compose.yml | 13 -- apix-docker/72/docker-compose.yml | 13 -- apix-docker/build.gradle | 31 +-- .../overrides.gradle => apix-impl/62/.gitkeep | 0 apix-impl/62/overrides.gradle | 9 - .../62/src/main/config/module.properties | 7 - apix-impl/70/.gitkeep | 0 apix-impl/70/overrides.gradle | 9 - .../70/src/main/config/module.properties | 7 - apix-impl/71/.gitkeep | 0 apix-impl/71/overrides.gradle | 9 - .../71/src/main/config/module.properties | 7 - apix-impl/72/.gitkeep | 0 apix-impl/72/overrides.gradle | 9 - .../72/src/main/config/module.properties | 7 - .../73/src/main/config/module.properties | 6 - apix-impl/build.gradle | 47 ++--- .../messages/faceted-search_en.properties | 26 +-- apix-impl/config/module-context.xml | 24 +-- apix-impl/src/main/config/module.properties | 1 - apix-integrationtests/62/overrides.gradle | 3 - apix-integrationtests/70/overrides.gradle | 3 - apix-integrationtests/71/overrides.gradle | 3 - apix-integrationtests/72/overrides.gradle | 3 - apix-integrationtests/alfresco/61/.gitkeep | 0 apix-integrationtests/alfresco/62/.gitkeep | 0 apix-integrationtests/alfresco/70/.gitkeep | 0 apix-integrationtests/alfresco/71/.gitkeep | 0 apix-integrationtests/alfresco/72/.gitkeep | 0 .../{ => alfresco}/build.gradle | 42 ++-- .../rest/staging/tests/StagingBaseTest.java | 0 .../apix/rest/staging/tests/WorkflowTest.java | 0 .../apix/rest/v1/tests/AllNodeInfoTest.java | 0 .../apix/rest/v1/tests/AssociationsTest.java | 0 .../eu/xenit/apix/rest/v1/tests/BulkTest.java | 0 .../rest/v1/tests/CheckoutCheckinTest.java | 0 .../apix/rest/v1/tests/CommentsTest.java | 0 .../apix/rest/v1/tests/ConfigurationTest.java | 0 .../apix/rest/v1/tests/CopyNodeTest.java | 0 .../apix/rest/v1/tests/CreateNodeTest.java | 0 .../apix/rest/v1/tests/DictionaryTest.java | 0 .../xenit/apix/rest/v1/tests/ExampleTest.java | 0 .../apix/rest/v1/tests/MetadataTest.java | 0 .../apix/rest/v1/tests/MoveNodeTest.java | 0 .../apix/rest/v1/tests/NodeContentTest.java | 0 .../apix/rest/v1/tests/NodesBaseTest.java | 0 .../eu/xenit/apix/rest/v1/tests/PathTest.java | 0 .../xenit/apix/rest/v1/tests/PeopleTest.java | 0 .../apix/rest/v1/tests/PermissionsTest.java | 0 .../apix/rest/v1/tests/RestV1BaseTest.java | 0 .../SetInheritParentPermissionsTest.java | 0 .../rest/v1/tests/VersionHistoryTest.java | 0 .../xenit/apix/rest/v1/tests/VersionTest.java | 0 .../v1/tests/resources/cyrillic_message.msg | Bin .../rest/v1/tests/temp/UploadFileTest.java | 0 .../v1/tests/temp/V1SearchWebscriptTest.java | 0 .../apix/rest/v2/tests/AllNodeInfoTest.java | 0 .../xenit/apix/rest/v2/tests/GroupTest.java | 0 .../xenit/apix/rest/v2/tests/PeopleTest.java | 0 .../apix/rest/v2/tests/RestV2BaseTest.java | 0 .../apix/tests/ApixImplBundleFilter.java | 0 .../java/eu/xenit/apix/tests/BaseTest.java | 24 +-- .../tests/categories/CategoryServiceTest.java | 0 .../tests/comments/CommentServiceTest.java | 0 .../tests/content/ContentServiceTest.java | 0 .../dictionary/DictionaryServiceTest.java | 0 .../filefolder/FileFolderServiceTest.java | 0 .../AlfrescoPropertyConvertorTest.java | 0 .../apix/tests/metadata/NodeServiceTest.java | 0 .../apix/tests/people/PeopleServiceTest.java | 0 .../permissions/PermissionServiceTest.java | 0 .../tests/properties/PropertyServiceTest.java | 0 .../apix/tests/search/FtsNodeVisitorTest.java | 0 .../apix/tests/search/QueryBuilderTest.java | 0 .../tests/search/SearchNodeParsingTest.java | 0 .../tests/search/SearchServiceFacetsTest.java | 49 ----- .../apix/tests/search/SearchServiceTest.java | 186 +++++++----------- .../tests/search/SearchSyntaxPrinterTest.java | 0 .../tests/search/TermHitHighlightingTest.java | 0 .../transaction/TransactionServiceTest.java | 1 - .../translation/TranslationServiceTest.java | 0 .../VersionHistoryServiceTest.java | 0 .../workflow/WorkflowServiceBaseTest.java | 0 .../WorkflowService_BaseMethod_Test.java | 0 ...WorkflowService_CancelMyWorkflow_Test.java | 0 ...ancelSomebodyElseWorkflowAsAdmin_Test.java | 0 ...rvice_CancelSomebodyElseWorkflow_Test.java | 0 ...wService_ClaimOnOtherPoolAsAdmin_Test.java | 0 ...WorkflowService_ClaimOnOtherPool_Test.java | 0 ...orkflowService_ClaimOnReviewTask_Test.java | 0 ...mReleaseWorkflowTaskOnPooledTask_Test.java | 0 ...TaskByIDIDontHaveAccessToAsAdmin_Test.java | 0 ...ice_GetTaskByIDIDontHaveAccessTo_Test.java | 0 ...Service_GetTaskByIDIHaveAccessTo_Test.java | 0 ...flowByIDIDontHaveAccessToAsAdmin_Test.java | 0 ...GetWorkflowByIDIDontHaveAccessTo_Test.java | 0 ...ice_GetWorkflowByIDIHaveAccessTo_Test.java | 0 ...eleaseOnOtherClaimedTasksAsAdmin_Test.java | 0 ...rvice_ReleaseOnOtherClaimedTasks_Test.java | 0 ...lowService_SearchContextAllTasks_Test.java | 0 ...rvice_SearchContextMyPooledTasks_Test.java | 0 ...flowService_SearchContextMyTasks_Test.java | 0 ...WorkflowService_TransitionMyTask_Test.java | 0 ...TransitionSomeoneElseTaskAsAdmin_Test.java | 0 ...ervice_TransitionSomeoneElseTask_Test.java | 0 .../WorkflowService_UpdateEmpty_Test.java | 0 ...lowService_UpdateMixedProperties_Test.java | 0 ...rvice_UpdateModifiableProperties_Test.java | 0 .../WorkflowService_UpdateNull_Test.java | 0 ...ice_UpdateUnmodifiableProperties_Test.java | 0 .../xenit/apix/util/AlfrescoServerInfo.java | 40 ++++ .../eu/xenit/apix/util/SolrAdminClient.java | 12 +- .../eu/xenit/apix/util/SolrTestHelper.java | 0 .../xenit/apix/util/SolrTestHelperImpl.java | 140 +++++++++++++ .../src/main/resources/cyrillic_message.msg | Bin .../main/resources/facet-forms-config.json | 0 .../apix/util/AlfrescoServerInfoTest.java | 22 +++ .../model-amp}/README.md | 0 .../model-amp}/build.gradle | 0 .../messages/apixtest.properties | 0 .../messages/apixtest_nl.properties | 0 .../model/apixtest-model.xml | 0 .../module-context.xml | 0 .../apix/util/SolrTestHelperBaseImpl.java | 136 ------------- apix-rest-v1/build.gradle | 6 +- .../java/eu/xenit/apix/rest/SpringConfig.java | 2 +- .../rest/v1/bulk/IntermediateResponse.java | 1 - .../apix/rest/v1/nodes/NodesWebscript1.java | 2 +- .../api.delete.desc.xml | 0 .../{alfred-rest => alfred}/api.get.desc.xml | 0 .../{alfred-rest => alfred}/api.post.desc.xml | 0 .../{alfred-rest => alfred}/api.put.desc.xml | 0 build.gradle | 38 ++-- settings.gradle | 47 ++--- 141 files changed, 441 insertions(+), 601 deletions(-) create mode 100644 alfresco/61/overrides.gradle create mode 100644 alfresco/62/overrides.gradle create mode 100644 alfresco/70/overrides.gradle create mode 100644 alfresco/71/overrides.gradle create mode 100644 alfresco/72/overrides.gradle rename apix-integrationtests/61/overrides.gradle => apix-impl/62/.gitkeep (100%) delete mode 100644 apix-impl/62/overrides.gradle delete mode 100644 apix-impl/62/src/main/config/module.properties create mode 100644 apix-impl/70/.gitkeep delete mode 100644 apix-impl/70/overrides.gradle delete mode 100644 apix-impl/70/src/main/config/module.properties create mode 100644 apix-impl/71/.gitkeep delete mode 100644 apix-impl/71/overrides.gradle delete mode 100644 apix-impl/71/src/main/config/module.properties create mode 100644 apix-impl/72/.gitkeep delete mode 100644 apix-impl/72/overrides.gradle delete mode 100644 apix-impl/72/src/main/config/module.properties delete mode 100644 apix-impl/73/src/main/config/module.properties delete mode 100644 apix-impl/src/main/config/module.properties delete mode 100644 apix-integrationtests/62/overrides.gradle delete mode 100644 apix-integrationtests/70/overrides.gradle delete mode 100644 apix-integrationtests/71/overrides.gradle delete mode 100644 apix-integrationtests/72/overrides.gradle create mode 100644 apix-integrationtests/alfresco/61/.gitkeep create mode 100644 apix-integrationtests/alfresco/62/.gitkeep create mode 100644 apix-integrationtests/alfresco/70/.gitkeep create mode 100644 apix-integrationtests/alfresco/71/.gitkeep create mode 100644 apix-integrationtests/alfresco/72/.gitkeep rename apix-integrationtests/{ => alfresco}/build.gradle (85%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/staging/tests/StagingBaseTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/staging/tests/WorkflowTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/AllNodeInfoTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/AssociationsTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/BulkTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/CheckoutCheckinTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/CommentsTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/DictionaryTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/ExampleTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/MetadataTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/MoveNodeTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/PathTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/PeopleTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/PermissionsTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/RestV1BaseTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/SetInheritParentPermissionsTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/VersionTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/resources/cyrillic_message.msg (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/temp/UploadFileTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v1/tests/temp/V1SearchWebscriptTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v2/tests/GroupTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v2/tests/PeopleTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/rest/v2/tests/RestV2BaseTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/ApixImplBundleFilter.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/BaseTest.java (87%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/categories/CategoryServiceTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/comments/CommentServiceTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/content/ContentServiceTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/dictionary/DictionaryServiceTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/filefolder/FileFolderServiceTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/metadata/AlfrescoPropertyConvertorTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/metadata/NodeServiceTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/people/PeopleServiceTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/permissions/PermissionServiceTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/properties/PropertyServiceTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/search/FtsNodeVisitorTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/search/QueryBuilderTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/search/SearchNodeParsingTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/search/SearchServiceFacetsTest.java (73%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/search/SearchServiceTest.java (66%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/search/SearchSyntaxPrinterTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/search/TermHitHighlightingTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/transaction/TransactionServiceTest.java (95%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/translation/TranslationServiceTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/versionhistory/VersionHistoryServiceTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/WorkflowServiceBaseTest.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_BaseMethod_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelMyWorkflow_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelSomebodyElseWorkflowAsAdmin_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelSomebodyElseWorkflow_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnOtherPoolAsAdmin_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnOtherPool_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnReviewTask_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimReleaseWorkflowTaskOnPooledTask_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIDontHaveAccessToAsAdmin_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIDontHaveAccessTo_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIHaveAccessTo_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIDontHaveAccessToAsAdmin_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIDontHaveAccessTo_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIHaveAccessTo_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ReleaseOnOtherClaimedTasksAsAdmin_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ReleaseOnOtherClaimedTasks_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextAllTasks_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextMyPooledTasks_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextMyTasks_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionMyTask_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionSomeoneElseTaskAsAdmin_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionSomeoneElseTask_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateEmpty_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateMixedProperties_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateModifiableProperties_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateNull_Test.java (100%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateUnmodifiableProperties_Test.java (100%) create mode 100644 apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/AlfrescoServerInfo.java rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/util/SolrAdminClient.java (86%) rename apix-integrationtests/{ => alfresco}/src/main/java/eu/xenit/apix/util/SolrTestHelper.java (100%) create mode 100644 apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java rename apix-integrationtests/{ => alfresco}/src/main/resources/cyrillic_message.msg (100%) rename apix-integrationtests/{ => alfresco}/src/main/resources/facet-forms-config.json (100%) create mode 100644 apix-integrationtests/alfresco/src/test/java/eu/xenit/apix/util/AlfrescoServerInfoTest.java rename {apix-integrationtests-model-amp => apix-integrationtests/model-amp}/README.md (100%) rename {apix-integrationtests-model-amp => apix-integrationtests/model-amp}/build.gradle (100%) rename {apix-integrationtests-model-amp => apix-integrationtests/model-amp}/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/messages/apixtest.properties (100%) rename {apix-integrationtests-model-amp => apix-integrationtests/model-amp}/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/messages/apixtest_nl.properties (100%) rename {apix-integrationtests-model-amp => apix-integrationtests/model-amp}/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/model/apixtest-model.xml (100%) rename {apix-integrationtests-model-amp => apix-integrationtests/model-amp}/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/module-context.xml (100%) delete mode 100644 apix-integrationtests/src/main/java/eu/xenit/apix/util/SolrTestHelperBaseImpl.java rename apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/{alfred-rest => alfred}/api.delete.desc.xml (100%) rename apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/{alfred-rest => alfred}/api.get.desc.xml (100%) rename apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/{alfred-rest => alfred}/api.post.desc.xml (100%) rename apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/{alfred-rest => alfred}/api.put.desc.xml (100%) diff --git a/alfresco/61/overrides.gradle b/alfresco/61/overrides.gradle new file mode 100644 index 00000000..a3f8f4f9 --- /dev/null +++ b/alfresco/61/overrides.gradle @@ -0,0 +1,5 @@ +ext { + alfresco_version = "6.1.2-ga" + alfresco_min_version = alfresco_version.substring(0, 3) + ".0" + alfresco_max_version = alfresco_version.substring(0, 3) + ".99" +} \ No newline at end of file diff --git a/alfresco/62/overrides.gradle b/alfresco/62/overrides.gradle new file mode 100644 index 00000000..0cf8430f --- /dev/null +++ b/alfresco/62/overrides.gradle @@ -0,0 +1,5 @@ +ext { + alfresco_version = "6.2.0-ga" + alfresco_min_version = alfresco_version.substring(0, 3) + ".0" + alfresco_max_version = alfresco_version.substring(0, 3) + ".99" +} \ No newline at end of file diff --git a/alfresco/70/overrides.gradle b/alfresco/70/overrides.gradle new file mode 100644 index 00000000..137528ec --- /dev/null +++ b/alfresco/70/overrides.gradle @@ -0,0 +1,5 @@ +ext { + alfresco_version = "7.0.0" + alfresco_min_version = alfresco_version.substring(0, 3) + ".0" + alfresco_max_version = alfresco_version.substring(0, 3) + ".99" +} \ No newline at end of file diff --git a/alfresco/71/overrides.gradle b/alfresco/71/overrides.gradle new file mode 100644 index 00000000..0fd91973 --- /dev/null +++ b/alfresco/71/overrides.gradle @@ -0,0 +1,5 @@ +ext { + alfresco_version = "7.1.1" + alfresco_min_version = alfresco_version.substring(0, 3) + ".0" + alfresco_max_version = alfresco_version.substring(0, 3) + ".99" +} \ No newline at end of file diff --git a/alfresco/72/overrides.gradle b/alfresco/72/overrides.gradle new file mode 100644 index 00000000..7a69687c --- /dev/null +++ b/alfresco/72/overrides.gradle @@ -0,0 +1,7 @@ +ext { + alfresco_version = "7.2.1" + alfresco_min_version = alfresco_version.substring(0, 3) + ".0" +} +if(project.hasProperty("alfresco_max_version")) { + project.properties.remove("alfresco_max_version") +} \ No newline at end of file diff --git a/apix-docker/62/docker-compose.yml b/apix-docker/62/docker-compose.yml index f290947b..3c09b18e 100644 --- a/apix-docker/62/docker-compose.yml +++ b/apix-docker/62/docker-compose.yml @@ -8,17 +8,6 @@ services: volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped - environment: - - SOLR_HOST=solr - - TERM=xterm - ## Needed for Solr indexing - - GLOBAL_local.transform.service.enabled=true - # Disable transformations and renditions - - GLOBAL_contentPropertyRestrictions.enabled=false - - GLOBAL_ooo.enabled=false - - GLOBAL_jodconverter.enabled=false - - GLOBAL_transform.service.enabled=false - - GLOBAL_legacy.transform.service.enabled=false solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 @@ -36,9 +25,9 @@ services: - POSTGRES_DB=alfresco restart: unless-stopped -# jodconverter: -# image: hub.xenit.eu/public/jodconverter-ws -# restart: unless-stopped + jodconverter: + image: hub.xenit.eu/public/jodconverter-ws + restart: unless-stopped volumes: alfresco: diff --git a/apix-docker/70/docker-compose.yml b/apix-docker/70/docker-compose.yml index b5b9f8ff..c90563cf 100644 --- a/apix-docker/70/docker-compose.yml +++ b/apix-docker/70/docker-compose.yml @@ -8,19 +8,6 @@ services: volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped - environment: - - SOLR_HOST=solr - - TERM=xterm - - GLOBAL_messaging.broker.url=failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true - - GLOBAL_localTransform.core-aio.url=http://transform-core-aio:8090/ - ## Needed for Solr indexing - - GLOBAL_local.transform.service.enabled=true - # Disable transformations and renditions - - GLOBAL_contentPropertyRestrictions.enabled=false - - GLOBAL_ooo.enabled=false - - GLOBAL_jodconverter.enabled=false - - GLOBAL_transform.service.enabled=false - - GLOBAL_legacy.transform.service.enabled=false solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 diff --git a/apix-docker/71/docker-compose.yml b/apix-docker/71/docker-compose.yml index b5b9f8ff..c90563cf 100644 --- a/apix-docker/71/docker-compose.yml +++ b/apix-docker/71/docker-compose.yml @@ -8,19 +8,6 @@ services: volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped - environment: - - SOLR_HOST=solr - - TERM=xterm - - GLOBAL_messaging.broker.url=failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true - - GLOBAL_localTransform.core-aio.url=http://transform-core-aio:8090/ - ## Needed for Solr indexing - - GLOBAL_local.transform.service.enabled=true - # Disable transformations and renditions - - GLOBAL_contentPropertyRestrictions.enabled=false - - GLOBAL_ooo.enabled=false - - GLOBAL_jodconverter.enabled=false - - GLOBAL_transform.service.enabled=false - - GLOBAL_legacy.transform.service.enabled=false solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 diff --git a/apix-docker/72/docker-compose.yml b/apix-docker/72/docker-compose.yml index ace92124..ea75e0aa 100644 --- a/apix-docker/72/docker-compose.yml +++ b/apix-docker/72/docker-compose.yml @@ -8,19 +8,6 @@ services: volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped - environment: - - SOLR_HOST=solr - - TERM=xterm - - GLOBAL_messaging.broker.url=failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true - - GLOBAL_localTransform.core-aio.url=http://transform-core-aio:8090/ - ## Needed for Solr indexing - - GLOBAL_local.transform.service.enabled=true - # Disable transformations and renditions - - GLOBAL_contentPropertyRestrictions.enabled=false - - GLOBAL_ooo.enabled=false - - GLOBAL_jodconverter.enabled=false - - GLOBAL_transform.service.enabled=false - - GLOBAL_legacy.transform.service.enabled=false solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 diff --git a/apix-docker/build.gradle b/apix-docker/build.gradle index 8239aa6d..bf1b8bca 100644 --- a/apix-docker/build.gradle +++ b/apix-docker/build.gradle @@ -1,13 +1,3 @@ -plugins { - id 'eu.xenit.docker-alfresco' version '5.3.1' apply false - id 'eu.xenit.docker-compose' version '5.3.1' apply false - id 'be.vbgn.ci-detect' version '0.5.0' apply false -} - -ext { - de_version = "2.1.3" -} - subprojects { apply plugin: 'eu.xenit.docker-alfresco' apply plugin: 'eu.xenit.docker-compose' @@ -23,7 +13,7 @@ subprojects { dependencies { alfrescoAmp project(path: ":apix-impl:apix-impl-${subproject_alfresco_version}", configuration: 'ampArtifact') - alfrescoAmp project(path: ':apix-integrationtests-model-amp', configuration: 'ampArchives') + alfrescoAmp project(path: ':apix-integrationtests:model-amp', configuration: 'ampArchives') alfrescoAmp project(path: ':apix-rest-v1', configuration: 'ampArtifact') alfrescoSM "com.gradecak.alfresco-mvc:alfresco-mvc-rest:$mvc" alfrescoSM "com.gradecak.alfresco-mvc:alfresco-mvc-aop:$mvc" @@ -41,6 +31,25 @@ subprojects { useComposeFiles.add(extraComposeFile) } } + + // Solr Tracking improvements +// environment.put 'GLOBAL_alfresco.cron', '0/2 * * * * ? *' +// environment.put 'GLOBAL_alfresco.lag', '500' +// environment.put 'GLOBAL_solr.http.socket.timeout','10000' + // Logging improvements + environment.put 'TERM', 'xterm' + if(subproject_alfresco_version.startsWith("7")) { + environment.put'GLOBAL_messaging.broker.url','failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true' + environment.put'GLOBAL_localTransform.core-aio.url','http://transform-core-aio:8090/' + // Needed for Solr indexing + environment.put 'GLOBAL_local.transform.service.enabled','true' + // Disable transformations and renditions + environment.put 'GLOBAL_contentPropertyRestrictions.enabled','false' + environment.put 'GLOBAL_ooo.enabled','false' + environment.put 'GLOBAL_jodconverter.enabled','false' + environment.put 'GLOBAL_transform.service.enabled','false' + environment.put 'GLOBAL_legacy.transform.service.enabled','false' + } } } diff --git a/apix-integrationtests/61/overrides.gradle b/apix-impl/62/.gitkeep similarity index 100% rename from apix-integrationtests/61/overrides.gradle rename to apix-impl/62/.gitkeep diff --git a/apix-impl/62/overrides.gradle b/apix-impl/62/overrides.gradle deleted file mode 100644 index 0042acd8..00000000 --- a/apix-impl/62/overrides.gradle +++ /dev/null @@ -1,9 +0,0 @@ -description = "Xenit API-X implementation Alfresco 6.2" - -ext { - alfresco_version = alfresco_62_version - alfresco_repo_version = '7.199.0' - alfresco_dm_version = alfresco_62_dm_version - alfresco_min_version = "6.2" - alfresco_max_version = "6.2.99" -} diff --git a/apix-impl/62/src/main/config/module.properties b/apix-impl/62/src/main/config/module.properties deleted file mode 100644 index c38166f0..00000000 --- a/apix-impl/62/src/main/config/module.properties +++ /dev/null @@ -1,7 +0,0 @@ -module.id=${project.name} -module.title=${project.name} -module.description=${project.description} -module.version=${project.version} - -module.repo.version.min=${project.alfresco_min_version} -module.repo.version.max=${project.alfresco_max_version} diff --git a/apix-impl/70/.gitkeep b/apix-impl/70/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apix-impl/70/overrides.gradle b/apix-impl/70/overrides.gradle deleted file mode 100644 index 762229b5..00000000 --- a/apix-impl/70/overrides.gradle +++ /dev/null @@ -1,9 +0,0 @@ -description = "Xenit API-X implementation Alfresco 7.0" - -ext { - alfresco_version = alfresco_70_version - alfresco_repo_version = '8.424' - alfresco_dm_version = alfresco_70_dm_version - alfresco_min_version = "7.0" - alfresco_max_version = "7.0.99" -} \ No newline at end of file diff --git a/apix-impl/70/src/main/config/module.properties b/apix-impl/70/src/main/config/module.properties deleted file mode 100644 index c38166f0..00000000 --- a/apix-impl/70/src/main/config/module.properties +++ /dev/null @@ -1,7 +0,0 @@ -module.id=${project.name} -module.title=${project.name} -module.description=${project.description} -module.version=${project.version} - -module.repo.version.min=${project.alfresco_min_version} -module.repo.version.max=${project.alfresco_max_version} diff --git a/apix-impl/71/.gitkeep b/apix-impl/71/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apix-impl/71/overrides.gradle b/apix-impl/71/overrides.gradle deleted file mode 100644 index 6da46b6a..00000000 --- a/apix-impl/71/overrides.gradle +++ /dev/null @@ -1,9 +0,0 @@ -description = "Xenit API-X implementation Alfresco 7.1" - -ext { - alfresco_version = alfresco_71_version - alfresco_repo_version = '12.23' - alfresco_dm_version = alfresco_71_dm_version - alfresco_min_version = "7.1" - alfresco_max_version = "7.1.99" -} \ No newline at end of file diff --git a/apix-impl/71/src/main/config/module.properties b/apix-impl/71/src/main/config/module.properties deleted file mode 100644 index c38166f0..00000000 --- a/apix-impl/71/src/main/config/module.properties +++ /dev/null @@ -1,7 +0,0 @@ -module.id=${project.name} -module.title=${project.name} -module.description=${project.description} -module.version=${project.version} - -module.repo.version.min=${project.alfresco_min_version} -module.repo.version.max=${project.alfresco_max_version} diff --git a/apix-impl/72/.gitkeep b/apix-impl/72/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apix-impl/72/overrides.gradle b/apix-impl/72/overrides.gradle deleted file mode 100644 index d4fce3cf..00000000 --- a/apix-impl/72/overrides.gradle +++ /dev/null @@ -1,9 +0,0 @@ -description = "Xenit API-X implementation Alfresco 7.2" - -ext { - alfresco_version = alfresco_72_version - alfresco_repo_version = '14.142' - alfresco_dm_version = alfresco_72_dm_version - alfresco_min_version = "7.2" - alfresco_max_version = "7.2.99" -} \ No newline at end of file diff --git a/apix-impl/72/src/main/config/module.properties b/apix-impl/72/src/main/config/module.properties deleted file mode 100644 index c38166f0..00000000 --- a/apix-impl/72/src/main/config/module.properties +++ /dev/null @@ -1,7 +0,0 @@ -module.id=${project.name} -module.title=${project.name} -module.description=${project.description} -module.version=${project.version} - -module.repo.version.min=${project.alfresco_min_version} -module.repo.version.max=${project.alfresco_max_version} diff --git a/apix-impl/73/src/main/config/module.properties b/apix-impl/73/src/main/config/module.properties deleted file mode 100644 index 18c2abc5..00000000 --- a/apix-impl/73/src/main/config/module.properties +++ /dev/null @@ -1,6 +0,0 @@ -module.id=${project.name} -module.title=${project.name} -module.description=${project.description} -module.version=${project.version} - -module.repo.version.min=${project.alfresco_min_version} diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index 79eedf40..88fd37d6 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -1,21 +1,7 @@ -plugins { - id 'eu.xenit.de' version '2.1.3' apply false - id 'eu.xenit.amp' version '1.1.0' apply false - id 'eu.xenit.alfresco' version '1.1.0' apply false -} - -// Give IntelliJ a default source of non-shared classes -ext { - alfresco_version = alfresco_62_version - alfresco_repo_version = '7.199.0' - alfresco_dm_version = alfresco_62_dm_version - alfresco_min_version = '6.2' -} - sourceSets.main.java.srcDirs += 'src/main/java' - subprojects { - apply from: "${project.projectDir}/overrides.gradle" + def shortAlfrescoVersion = project.name.split("-")[2] + apply from: "${rootProject.projectDir}/alfresco/$shortAlfrescoVersion/overrides.gradle" apply from: "${rootProject.projectDir}/publish.gradle" apply plugin: 'eu.xenit.amp' apply plugin: 'java-library' @@ -44,23 +30,34 @@ subprojects { sourceSets { main { java { - srcDirs = ['src/main/java', '../src/main/java'] + srcDirs = ["$project.parent.projectDir/src/main/java"] } amp { - module("src/main/config/module.properties") + module { + it.put("module.id", project.name) + it.put("module.title", project.name) + it.put("module.description", + "Xenit API-X implementation Alfresco ${alfresco_version.substring(0, 3)}") + it.put("module.version", project.version) + it.put("module.repo.version.min", project.alfresco_min_version) + if(project.hasProperty("alfresco_max_version")) { + it.put("module.repo.version.max", project.alfresco_max_version) + } + } + } } test { java { - srcDirs = ['../src/test/java'] + srcDirs = ["$project.parent.projectDir/src/test/java"] } - testResultsDirName = "${buildDir}/test-results/test" + testResultsDirName = "${project.parent.buildDir}/test-results/test" } } // Extend amp plugin task: // We want to add 'alfresco-global.properties' etc to the module-specific folder in the AMP - // (e.g. 'config/module/alfresco/module/apix-impl-72/') without hard-coding project name for each Alfresco version. + // (e.g. 'config/module/alfresco/module/apix-impl-61/') without hard-coding project name for each Alfresco version. amp { into("config/alfresco/module/${project.name}") { from("${project.parent.projectDir}/config/alfresco-global.properties") @@ -79,6 +76,10 @@ subprojects { } allprojects { + // Subproject of supported Alfresco version 61/62/70/71/72 + def subproject_alfresco_version = project.projectDir.name == "apix-impl" + ? "70" : project.projectDir.name + apply from: "$rootProject.projectDir/alfresco/$subproject_alfresco_version/overrides.gradle" // allprojects also applies to shared code (under apix-impl/src) that needs to work in IntelliJ apply plugin: 'eu.xenit.alfresco' apply plugin: 'java-library' @@ -87,14 +88,14 @@ allprojects { api(project(":apix-interface")) implementation 'commons-lang:commons-lang:1.0' - alfrescoProvided platform("org.alfresco:acs-community-packaging:$alfrescoVersion") + alfrescoProvided platform("org.alfresco:acs-community-packaging:$alfresco_version") alfrescoProvided("org.alfresco:alfresco-repository") alfrescoProvided('org.alfresco:alfresco-remote-api') implementation group: 'org.yaml', name: 'snakeyaml', version: '1.15' implementation group: 'javax.validation', name: 'validation-api', version: '1.1.0.Final' - testImplementation platform("org.alfresco:acs-community-packaging:$alfrescoVersion") + testImplementation platform("org.alfresco:acs-community-packaging:$alfresco_version") testImplementation 'org.alfresco:alfresco-repository' testImplementation 'org.alfresco:alfresco-remote-api' testImplementation 'org.alfresco:alfresco-data-model' diff --git a/apix-impl/config/messages/faceted-search_en.properties b/apix-impl/config/messages/faceted-search_en.properties index 6d623180..f8bff925 100644 --- a/apix-impl/config/messages/faceted-search_en.properties +++ b/apix-impl/config/messages/faceted-search_en.properties @@ -1,14 +1,14 @@ -# Hard-coded date "buckets"... -faceted-search.date.one-day.label=Today -faceted-search.date.one-week.label=This week -faceted-search.date.one-month.label=This month -faceted-search.date.six-months.label=In the last 6 months -faceted-search.date.one-year.label=This year - -# Hard-coded size "buckets"... -faceted-search.size.0-10KB.label=0 to 10KB -faceted-search.size.10-100KB.label=10 to 100KB -faceted-search.size.100KB-1MB.label=100KB to 1MB -faceted-search.size.1-16MB.label=1 to 16MB -faceted-search.size.16-128MB.label=16 to 128MB +# Hard-coded date "buckets"... +faceted-search.date.one-day.label=Today +faceted-search.date.one-week.label=This week +faceted-search.date.one-month.label=This month +faceted-search.date.six-months.label=In the last 6 months +faceted-search.date.one-year.label=This year + +# Hard-coded size "buckets"... +faceted-search.size.0-10KB.label=0 to 10KB +faceted-search.size.10-100KB.label=10 to 100KB +faceted-search.size.100KB-1MB.label=100KB to 1MB +faceted-search.size.1-16MB.label=1 to 16MB +faceted-search.size.16-128MB.label=16 to 128MB faceted-search.size.over128.label=Bigger than 128MB \ No newline at end of file diff --git a/apix-impl/config/module-context.xml b/apix-impl/config/module-context.xml index e2b287de..4dec26a9 100644 --- a/apix-impl/config/module-context.xml +++ b/apix-impl/config/module-context.xml @@ -1,13 +1,13 @@ - - - - - - - alfresco/module/${moduleId}/messages/faceted-search - - - + + + + + + + alfresco/module/${moduleId}/messages/faceted-search + + + \ No newline at end of file diff --git a/apix-impl/src/main/config/module.properties b/apix-impl/src/main/config/module.properties deleted file mode 100644 index 7539abd7..00000000 --- a/apix-impl/src/main/config/module.properties +++ /dev/null @@ -1 +0,0 @@ -# Unused. Only exists to simplify apix-impl/build.gradle \ No newline at end of file diff --git a/apix-integrationtests/62/overrides.gradle b/apix-integrationtests/62/overrides.gradle deleted file mode 100644 index a770658c..00000000 --- a/apix-integrationtests/62/overrides.gradle +++ /dev/null @@ -1,3 +0,0 @@ -ext { - alfresco_version = "6.2.0-ga" -} \ No newline at end of file diff --git a/apix-integrationtests/70/overrides.gradle b/apix-integrationtests/70/overrides.gradle deleted file mode 100644 index be985b0d..00000000 --- a/apix-integrationtests/70/overrides.gradle +++ /dev/null @@ -1,3 +0,0 @@ -ext { - alfresco_version = "7.0.0" -} \ No newline at end of file diff --git a/apix-integrationtests/71/overrides.gradle b/apix-integrationtests/71/overrides.gradle deleted file mode 100644 index 1f5276eb..00000000 --- a/apix-integrationtests/71/overrides.gradle +++ /dev/null @@ -1,3 +0,0 @@ -ext { - alfresco_version = "7.1.1" -} \ No newline at end of file diff --git a/apix-integrationtests/72/overrides.gradle b/apix-integrationtests/72/overrides.gradle deleted file mode 100644 index f34112bd..00000000 --- a/apix-integrationtests/72/overrides.gradle +++ /dev/null @@ -1,3 +0,0 @@ -ext { - alfresco_version = "7.2.1" -} \ No newline at end of file diff --git a/apix-integrationtests/alfresco/61/.gitkeep b/apix-integrationtests/alfresco/61/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apix-integrationtests/alfresco/62/.gitkeep b/apix-integrationtests/alfresco/62/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apix-integrationtests/alfresco/70/.gitkeep b/apix-integrationtests/alfresco/70/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apix-integrationtests/alfresco/71/.gitkeep b/apix-integrationtests/alfresco/71/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apix-integrationtests/alfresco/72/.gitkeep b/apix-integrationtests/alfresco/72/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apix-integrationtests/build.gradle b/apix-integrationtests/alfresco/build.gradle similarity index 85% rename from apix-integrationtests/build.gradle rename to apix-integrationtests/alfresco/build.gradle index 76fd8266..3a1cd818 100644 --- a/apix-integrationtests/build.gradle +++ b/apix-integrationtests/alfresco/build.gradle @@ -1,23 +1,17 @@ -plugins { - id 'base' - id 'eu.xenit.de' version '2.1.3' apply false - id 'eu.xenit.alfresco' version '1.1.0' apply false - id 'eu.xenit.alfresco-remote-testrunner' version '2.0.1' apply false -} - def integrationTestsProjectDir = project.projectDir allprojects { // Subproject of supported Alfresco version 61/62/70/71/72 - def subproject_alfresco_version = project.projectDir.name == "apix-integrationtests" - ? "61" // minimum supported version + def subproject_alfresco_version = project.projectDir.name == "alfresco" + ? "70" // minimum supported version : project.projectDir.name // Following needs to apply to shared (./src) project and version-specific (e.g. ./70) projects. apply plugin: 'idea' + apply plugin: 'java-library' apply plugin: 'eu.xenit.de' apply plugin: 'eu.xenit.alfresco-remote-testrunner' apply plugin: 'eu.xenit.alfresco' - apply from: "$integrationTestsProjectDir/$subproject_alfresco_version/overrides.gradle" + apply from: "$rootProject.projectDir/alfresco/$subproject_alfresco_version/overrides.gradle" sourceSets { main.java.srcDirs = [] @@ -28,6 +22,10 @@ allprojects { configurations { implementation { + // Fixes IDE source highlighting + extendsFrom integrationTestImplementation + } + testImplementation { extendsFrom integrationTestImplementation } integrationTestImplementationLocal { @@ -38,10 +36,11 @@ allprojects { } dependencies { - alfrescoProvided project(":apix-rest-v1") - alfrescoProvided project(":apix-interface") + alfrescoProvided(project(":apix-rest-v1")) { transitive = false } + alfrescoProvided(project(":apix-interface")) { transitive = false } + // Add services used to the integration test fatjar, since we can't access the ones deployed in Alfresco - integrationTestImplementationRemote (project(":apix-impl:apix-impl-$subproject_alfresco_version")) { + integrationTestImplementationRemote(project(":apix-impl:apix-impl-$subproject_alfresco_version")) { // Already includes apix-interface, we need to exclude it to avoid Linkage errors from // having 2 of the same classes on the classpath // (1 in Alfresco from apix-impl AMP + 1 in DE from the integration tests fat jar) @@ -53,12 +52,6 @@ allprojects { exclude group: 'org.apache.httpcomponents', module: 'httpcore' } - alfrescoProvided platform("org.alfresco:acs-community-packaging:$alfrescoVersion") - alfrescoProvided("org.alfresco:alfresco-repository") - alfrescoProvided('org.alfresco:alfresco-remote-api') - alfrescoProvided('org.alfresco:alfresco-data-model') - alfrescoProvided group: 'org.osgi', name: 'org.osgi.core', version: '4.3.1' - // Below is a temporary fix to circumvent using commons-lang 1.0.0 JAR. This jar // - is injected by alfresco-remote-testrunner // - is not on Maven Central (only 1.0) is @@ -67,6 +60,15 @@ allprojects { // Ergo, kill it with fire. // The proper way is a fix of alfresco-remote-testrunner, but until then we use this workaround. integrationTestImplementationLocal "commons-lang:commons-lang:1.0" + + alfrescoProvided platform("org.alfresco:acs-community-packaging:$alfresco_version") + alfrescoProvided("org.alfresco:alfresco-repository") + alfrescoProvided('org.alfresco:alfresco-remote-api') + alfrescoProvided('org.alfresco:alfresco-data-model') + alfrescoProvided group: 'org.osgi', name: 'org.osgi.core', version: '4.3.1' + + testImplementation project.sourceSets.integrationTest.output + testImplementation group: 'org.mockito', name: 'mockito-core', version: '2.25.1' } } @@ -102,7 +104,7 @@ subprojects { dependsOn composeUpTask doFirst { def serviceInfo = composeUpTask.servicesInfos.get("alfresco-core") - if(serviceInfo != null) { + if (serviceInfo != null) { alfrescoDynamicExtensions { repository { endpoint { diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/staging/tests/StagingBaseTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/staging/tests/StagingBaseTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/staging/tests/StagingBaseTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/staging/tests/StagingBaseTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/staging/tests/WorkflowTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/staging/tests/WorkflowTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/staging/tests/WorkflowTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/staging/tests/WorkflowTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/AllNodeInfoTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/AllNodeInfoTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/AllNodeInfoTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/AllNodeInfoTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/AssociationsTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/AssociationsTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/AssociationsTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/AssociationsTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/BulkTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/BulkTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/BulkTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/BulkTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CheckoutCheckinTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/CheckoutCheckinTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CheckoutCheckinTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/CheckoutCheckinTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CommentsTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/CommentsTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CommentsTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/CommentsTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/CreateNodeTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/DictionaryTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/DictionaryTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/DictionaryTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/DictionaryTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/ExampleTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/ExampleTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/ExampleTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/ExampleTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/MetadataTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/MetadataTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/MetadataTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/MetadataTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/MoveNodeTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/MoveNodeTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/MoveNodeTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/MoveNodeTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/NodeContentTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/PathTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/PathTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/PathTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/PathTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/PeopleTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/PeopleTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/PeopleTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/PeopleTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/PermissionsTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/PermissionsTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/PermissionsTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/PermissionsTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/RestV1BaseTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/RestV1BaseTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/RestV1BaseTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/RestV1BaseTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/SetInheritParentPermissionsTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/SetInheritParentPermissionsTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/SetInheritParentPermissionsTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/SetInheritParentPermissionsTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/VersionTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/VersionTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/VersionTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/VersionTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/resources/cyrillic_message.msg b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/resources/cyrillic_message.msg similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/resources/cyrillic_message.msg rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/resources/cyrillic_message.msg diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/temp/UploadFileTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/temp/UploadFileTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/temp/UploadFileTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/temp/UploadFileTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/temp/V1SearchWebscriptTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/temp/V1SearchWebscriptTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v1/tests/temp/V1SearchWebscriptTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/temp/V1SearchWebscriptTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v2/tests/GroupTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v2/tests/GroupTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v2/tests/GroupTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v2/tests/GroupTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v2/tests/PeopleTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v2/tests/PeopleTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v2/tests/PeopleTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v2/tests/PeopleTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/rest/v2/tests/RestV2BaseTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v2/tests/RestV2BaseTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/rest/v2/tests/RestV2BaseTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v2/tests/RestV2BaseTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/ApixImplBundleFilter.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/ApixImplBundleFilter.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/ApixImplBundleFilter.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/ApixImplBundleFilter.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/BaseTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/BaseTest.java similarity index 87% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/BaseTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/BaseTest.java index 10ac6c26..9b8024bb 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/BaseTest.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/BaseTest.java @@ -2,13 +2,10 @@ import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.util.SolrTestHelper; -import eu.xenit.apix.util.SolrTestHelperImpl; import eu.xenit.testing.integrationtesting.runner.AlfrescoTestRunner; import eu.xenit.testing.integrationtesting.runner.UseSpringContextOfBundle; import java.util.Properties; -import javax.sql.DataSource; import org.alfresco.model.ContentModel; -import org.alfresco.repo.management.subsystems.SwitchableApplicationContextFactory; import org.alfresco.repo.model.Repository; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.model.FileFolderService; @@ -21,7 +18,6 @@ import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import java.io.File; import java.io.IOException; @@ -31,7 +27,7 @@ @RunWith(AlfrescoTestRunner.class) @UseSpringContextOfBundle(filter = ApixImplBundleFilter.class) -public abstract class BaseTest implements InitializingBean { +public abstract class BaseTest { //Apix Test model contstants public static final String APIX_TESTCM_NAMESPACE = "http://test.apix.xenit.eu/model/content"; @@ -50,23 +46,15 @@ public abstract class BaseTest implements InitializingBean { @Autowired protected Repository repository; @Autowired - DataSource dataSource; - @Autowired - @Qualifier("Search") - SwitchableApplicationContextFactory searchSubSystem; - @Autowired @Qualifier("global-properties") Properties globalProperties; - - public SolrTestHelper solrHelper; - - public void afterPropertiesSet() { - String subsystem = globalProperties.getProperty("index.subsystem.name"); - String solrBaseUrl = subsystem.equals("solr4") ? "/solr4" : "/solr"; - solrHelper = new SolrTestHelperImpl(solrBaseUrl, dataSource, searchSubSystem); - } + @Autowired + protected SolrTestHelper solrHelper; protected NodeRef getNodeAtPath(String path) { + if("/app:company_home".equals(path)) { + return repository.getCompanyHome(); + } SearchService searchService = serviceRegistry.getSearchService(); StoreRef storeRef = StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; ResultSet resultSet = searchService.query(storeRef, SearchService.LANGUAGE_XPATH, path); diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/categories/CategoryServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/categories/CategoryServiceTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/categories/CategoryServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/categories/CategoryServiceTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/comments/CommentServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/comments/CommentServiceTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/comments/CommentServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/comments/CommentServiceTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/content/ContentServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/content/ContentServiceTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/content/ContentServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/content/ContentServiceTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/dictionary/DictionaryServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/dictionary/DictionaryServiceTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/dictionary/DictionaryServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/dictionary/DictionaryServiceTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/filefolder/FileFolderServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/filefolder/FileFolderServiceTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/filefolder/FileFolderServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/filefolder/FileFolderServiceTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/metadata/AlfrescoPropertyConvertorTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/metadata/AlfrescoPropertyConvertorTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/metadata/AlfrescoPropertyConvertorTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/metadata/AlfrescoPropertyConvertorTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/metadata/NodeServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/metadata/NodeServiceTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/metadata/NodeServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/metadata/NodeServiceTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/people/PeopleServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/people/PeopleServiceTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/people/PeopleServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/people/PeopleServiceTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/permissions/PermissionServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/permissions/PermissionServiceTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/permissions/PermissionServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/permissions/PermissionServiceTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/properties/PropertyServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/properties/PropertyServiceTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/properties/PropertyServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/properties/PropertyServiceTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/FtsNodeVisitorTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/FtsNodeVisitorTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/FtsNodeVisitorTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/FtsNodeVisitorTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/QueryBuilderTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/QueryBuilderTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/QueryBuilderTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/QueryBuilderTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchNodeParsingTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/SearchNodeParsingTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchNodeParsingTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/SearchNodeParsingTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceFacetsTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/SearchServiceFacetsTest.java similarity index 73% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceFacetsTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/SearchServiceFacetsTest.java index fb44832e..1996e0a0 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceFacetsTest.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/SearchServiceFacetsTest.java @@ -15,7 +15,6 @@ import org.alfresco.repo.search.impl.solr.facet.SolrFacetProperties; import org.alfresco.repo.search.impl.solr.facet.SolrFacetService; import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.namespace.QName; import org.junit.Assert; import org.junit.Before; @@ -39,54 +38,6 @@ public void Setup() { AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER_NAME); } - @Override - protected void withTestFacets(final RunAsWork work) throws Exception { - SolrFacetProperties languageFacet = new SolrFacetProperties.Builder() - .filterID("document_language") - .facetQName(APIXTEST_LANGUAGE) - .displayControl("Simple Filter") - .displayName("Language") - .maxFilters(10) - .hitThreshold(1) - .minFilterValueLength(1) - .sortBy("ASCENDING") - .scope("ALL") - .isEnabled(true) - .isDefault(true) - .build(); - - final SolrFacetProperties documentStatusFacet = new SolrFacetProperties.Builder() - .filterID("document_status") - .facetQName(APIXTEST_DOCUMENT_STATUS) - .displayControl("Simple Filter") - .displayName("Status") - .maxFilters(10) - .hitThreshold(1) - .minFilterValueLength(1) - .sortBy("ASCENDING") - .scope("ALL") - .isEnabled(true) - .isDefault(true) - .build(); - - withFacet(languageFacet, new RunAsWork() { - @Override - public Object doWork() throws Exception { - withFacet(documentStatusFacet, work); - return null; - } - }); - - } - private void withFacet(SolrFacetProperties facetProperties, AuthenticationUtil.RunAsWork work) throws Exception { - facetService.createFacetNode(facetProperties); - try { - work.doWork(); - } finally { - facetService.deleteFacet(facetProperties.getFilterID()); - } - } - @Test public void TestGetWithFacetsIncludesCustomFilterFacets() throws InterruptedException { solrHelper.waitForTransactionSync(); diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/SearchServiceTest.java similarity index 66% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/SearchServiceTest.java index fa2895e3..5f767e15 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchServiceTest.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/SearchServiceTest.java @@ -11,16 +11,14 @@ import eu.xenit.apix.search.SearchQueryResult; import eu.xenit.apix.search.nodes.SearchSyntaxNode; import eu.xenit.apix.tests.BaseTest; -import java.io.IOException; import java.io.Serializable; import java.math.BigInteger; import java.util.HashMap; -import java.util.Locale; import java.util.Map; + import org.alfresco.model.ContentModel; import org.alfresco.repo.model.Repository; import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.model.FileInfo; @@ -38,15 +36,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.extensions.surf.util.I18NUtil; -abstract public class SearchServiceTest extends BaseTest { +public abstract class SearchServiceTest extends BaseTest { private static final String LONG_MAX_VALUE = String.valueOf(Long.MAX_VALUE); private static final String LONG_MAX_VALUE_PLUS_ONE = new BigInteger(LONG_MAX_VALUE).add(new BigInteger("1")) .toString(); - private final static Logger logger = LoggerFactory.getLogger(SearchServiceTest.class); + private static final Logger logger = LoggerFactory.getLogger(SearchServiceTest.class); private static final String ADMIN_USER_NAME = "admin"; public static final String DESCRIPTION_SET_OF_1001 = "descriptionSetOf1001"; @Autowired @@ -63,10 +60,6 @@ abstract public class SearchServiceTest extends BaseTest { @Autowired NamespacePrefixResolver namespacePrefixResolver; - final protected static String APIXTEST_NS = "http://test.apix.xenit.eu/model/content"; - final protected static QName APIXTEST_LANGUAGE = QName.createQName(APIXTEST_NS, "language"); - final protected static QName APIXTEST_DOCUMENT_STATUS = QName.createQName(APIXTEST_NS, "documentStatus"); - @Before public void Setup() { AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER_NAME); @@ -78,8 +71,7 @@ public void tearDown() { } @Test - public void TestGetWithoutFacets() throws IOException, InterruptedException { - solrHelper.waitForTransactionSync(); + public void TestGetWithoutFacets() { QueryBuilder builder = new QueryBuilder(); SearchSyntaxNode node = builder.term("type", "cm:folder").create(); @@ -93,8 +85,7 @@ public void TestGetWithoutFacets() throws IOException, InterruptedException { } @Test - public void TestGetWithFacets() throws IOException, InterruptedException { - solrHelper.waitForTransactionSync(); + public void TestGetWithFacets() { QueryBuilder builder = new QueryBuilder(); SearchSyntaxNode node = builder.term("type", "cm:content").create(); @@ -116,8 +107,7 @@ public void TestGetWithFacets() throws IOException, InterruptedException { } @Test - public void TestLimit() throws IOException, InterruptedException { - solrHelper.waitForTransactionSync(); + public void TestLimit() { QueryBuilder builder = new QueryBuilder(); SearchSyntaxNode node = builder.term("type", "cm:folder").create(); @@ -130,8 +120,7 @@ public void TestLimit() throws IOException, InterruptedException { } @Test - public void TestSkip() throws IOException, InterruptedException { - solrHelper.waitForTransactionSync(); + public void TestSkip() { QueryBuilder builder = new QueryBuilder(); eu.xenit.apix.search.nodes.SearchSyntaxNode node = builder.term("type", "cm:folder").create(); @@ -152,20 +141,17 @@ public void TestSkip() throws IOException, InterruptedException { } @Test - public void TestTotalCount() throws IOException, InterruptedException { + public void TestTotalCount() throws InterruptedException { transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public NodeRef execute() throws Throwable { + .doInTransaction((RetryingTransactionCallback) () -> { - NodeRef companyHomeRef = repository.getCompanyHome(); + NodeRef companyHomeRef = repository.getCompanyHome(); - FileInfo mainTestFolder = createMainTestFolder(companyHomeRef); - FileInfo testFolder = createTestFolder(mainTestFolder.getNodeRef(), "testFolder"); - FileInfo testNode = createTestNode(testFolder.getNodeRef(), "testNode"); - FileInfo testNode2 = createTestNode(testFolder.getNodeRef(), "testNode2"); - return null; - } + FileInfo mainTestFolder = createMainTestFolder(companyHomeRef); + FileInfo testFolder = createTestFolder(mainTestFolder.getNodeRef(), "testFolder"); + FileInfo testNode = createTestNode(testFolder.getNodeRef(), "testNode"); + FileInfo testNode2 = createTestNode(testFolder.getNodeRef(), "testNode2"); + return null; }, false, true); solrHelper.waitForTransactionSync(); @@ -173,24 +159,21 @@ public NodeRef execute() throws Throwable { Thread.sleep(15000); transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public NodeRef execute() throws Throwable { - QueryBuilder builder = new QueryBuilder(); - SearchSyntaxNode node = builder.property( - ContentModel.PROP_NAME.toPrefixString(namespacePrefixResolver), - "testNode", - false) - .create(); - - SearchQuery query = new SearchQuery(); - query.setQuery(node); - SearchQueryResult result = searchService.query(query); - - logger.debug("Total: " + result.getTotalResultCount()); - Assert.assertEquals(2, result.getTotalResultCount()); - return null; - } + .doInTransaction((RetryingTransactionCallback) () -> { + QueryBuilder builder = new QueryBuilder(); + SearchSyntaxNode node = builder.property( + ContentModel.PROP_NAME.toPrefixString(namespacePrefixResolver), + "testNode", + false) + .create(); + + SearchQuery query = new SearchQuery(); + query.setQuery(node); + SearchQueryResult result = searchService.query(query); + + logger.debug("Total: " + result.getTotalResultCount()); + assertEquals(2, result.getTotalResultCount()); + return null; }, false, true); } @@ -201,11 +184,11 @@ private void create1001TestDocs() throws InterruptedException { FileInfo mainTestFolder = createMainTestFolder(companyHomeRef); FileInfo testFolder = createTestFolder(mainTestFolder.getNodeRef(), "testFolderSetOf1001"); - Map props = new HashMap() {{ - put(QName.createQName(APIX_TESTCM_NAMESPACE, - APIX_TESTCM_PROP_SEARCHSERVICELIMITTEST_SHORTNAME), - DESCRIPTION_SET_OF_1001); - }}; + Map props = new HashMap<>(); + props.put( + QName.createQName(APIX_TESTCM_NAMESPACE, APIX_TESTCM_PROP_SEARCHSERVICELIMITTEST_SHORTNAME), + DESCRIPTION_SET_OF_1001 + ); for (int i = 0; i < 1001 ; i++) { FileInfo testNode = createTestNode(testFolder.getNodeRef(), "testNode-1001-" + i); nodeService.addProperties(testNode.getNodeRef(), props); @@ -280,8 +263,7 @@ public void TestLimitedByMaxPermissionChecks_eventual() throws InterruptedExcept } @Test - public void testPropertyRange() throws IOException, InterruptedException { - solrHelper.waitForTransactionSync(); + public void testPropertyRange() { QueryBuilder builder = new QueryBuilder(); SearchSyntaxNode node = builder .property("cm:created", "2010-01-01T00:00:00", "2015-01-01T00:00:00").create(); @@ -309,63 +291,55 @@ public static void waitAWhile(int nbSeconds) throws InterruptedException { * should always work. */ @Test - public void TestQueryConsistency_Transactional() throws InterruptedException { - solrHelper.waitForTransactionSync(); + public void TestQueryConsistency_Transactional() { final String theTitle = "The title to search for in SearchService.TestQueryConsistency_Transactional" + System.nanoTime(); final NodeRef theNewNode = transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public NodeRef execute() throws Throwable { - cleanUp(); - NodeRef companyHomeRef = repository.getCompanyHome(); - FileInfo mainTestFolder = createMainTestFolder(companyHomeRef); - - // create node - ChildAssociationRef testFolderAssoc = serviceRegistry.getNodeService() - .createNode(mainTestFolder.getNodeRef(), ContentModel.ASSOC_CONTAINS, - org.alfresco.service.namespace.QName - .createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "aNode.txt"), - ContentModel.TYPE_CONTENT); - NodeRef theNewNode = testFolderAssoc.getChildRef(); - - Map props = serviceRegistry - .getNodeService() - .getProperties(theNewNode); - props.put(ContentModel.PROP_TITLE, theTitle); - serviceRegistry.getNodeService().setProperties(theNewNode, props); - return theNewNode; - } + .doInTransaction(() -> { + cleanUp(); + NodeRef companyHomeRef = repository.getCompanyHome(); + FileInfo mainTestFolder = createMainTestFolder(companyHomeRef); + + // create node + ChildAssociationRef testFolderAssoc = serviceRegistry.getNodeService() + .createNode(mainTestFolder.getNodeRef(), ContentModel.ASSOC_CONTAINS, + QName + .createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "aNode.txt"), + ContentModel.TYPE_CONTENT); + NodeRef theNewNode1 = testFolderAssoc.getChildRef(); + + Map props = serviceRegistry + .getNodeService() + .getProperties(theNewNode1); + props.put(ContentModel.PROP_TITLE, theTitle); + serviceRegistry.getNodeService().setProperties(theNewNode1, props); + return theNewNode1; }, false, true); // Don't wait, immediately do a search transactionService.getRetryingTransactionHelper() - .doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() { - @Override - public Boolean execute() throws Throwable { - QueryBuilder builder = new QueryBuilder(); - eu.xenit.apix.search.nodes.SearchSyntaxNode node = builder - .property("cm:title", theTitle, true) - .create(); // Exact match is required - SearchQuery query = new SearchQuery(); - query.setQuery(node); - query.setConsistency(SearchQueryConsistency.TRANSACTIONAL); - SearchQueryResult result = searchService.query(query); - - assertTrue( - "Should find back the new node immediately when using transactional consistency!", - result.getNoderefs().contains(theNewNode.toString())); - - return Boolean.TRUE; - } + .doInTransaction(() -> { + QueryBuilder builder = new QueryBuilder(); + SearchSyntaxNode node = builder + .property("cm:title", theTitle, true) + .create(); // Exact match is required + SearchQuery query = new SearchQuery(); + query.setQuery(node); + query.setConsistency(SearchQueryConsistency.TRANSACTIONAL); + SearchQueryResult result = searchService.query(query); + + assertTrue( + "Should find back the new node immediately when using transactional consistency!", + result.getNoderefs().contains(theNewNode.toString())); + + return Boolean.TRUE; }, false, true); } @Test - public void TestExactMatchProperty() throws IOException, InterruptedException { - solrHelper.waitForTransactionSync(); + public void TestExactMatchProperty() { QueryBuilder builder = new QueryBuilder(); SearchSyntaxNode node = builder.property("cm:name", "Company Home", true).create(); // Exact match @@ -387,22 +361,6 @@ public void TestExactMatchProperty() throws IOException, InterruptedException { result.getNoderefs().get(0)); } - private void withLocale(Locale locale, AuthenticationUtil.RunAsWork work) throws Exception { - Locale prevLocale = I18NUtil.getLocale(); - I18NUtil.setLocale(locale); - - try { - work.doWork(); - } finally { - I18NUtil.setLocale(prevLocale); - } - } - - /** - * Implemented in alfresco version specific subclasses to set up and tear down solr facets. - */ - abstract protected void withTestFacets(AuthenticationUtil.RunAsWork work) throws Exception; - @Test public void validLong_onlyNode_doesNotThrowException() { diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchSyntaxPrinterTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/SearchSyntaxPrinterTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/SearchSyntaxPrinterTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/SearchSyntaxPrinterTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/TermHitHighlightingTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/TermHitHighlightingTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/search/TermHitHighlightingTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/search/TermHitHighlightingTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/transaction/TransactionServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/transaction/TransactionServiceTest.java similarity index 95% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/transaction/TransactionServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/transaction/TransactionServiceTest.java index 7c99e252..76e55e6c 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/transaction/TransactionServiceTest.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/transaction/TransactionServiceTest.java @@ -21,7 +21,6 @@ public class TransactionServiceTest extends BaseTest { ITransactionService service; @Autowired IFileFolderService ffservice; - private int four = 4; //dummy variable to skip compile time checks. Dont change this please public FileInfo Setup() { this.cleanUp(); diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/translation/TranslationServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/translation/TranslationServiceTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/translation/TranslationServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/translation/TranslationServiceTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/versionhistory/VersionHistoryServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/versionhistory/VersionHistoryServiceTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/versionhistory/VersionHistoryServiceTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/versionhistory/VersionHistoryServiceTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/WorkflowServiceBaseTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/WorkflowServiceBaseTest.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/WorkflowServiceBaseTest.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/WorkflowServiceBaseTest.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_BaseMethod_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_BaseMethod_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_BaseMethod_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_BaseMethod_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelMyWorkflow_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelMyWorkflow_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelMyWorkflow_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelMyWorkflow_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelSomebodyElseWorkflowAsAdmin_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelSomebodyElseWorkflowAsAdmin_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelSomebodyElseWorkflowAsAdmin_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelSomebodyElseWorkflowAsAdmin_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelSomebodyElseWorkflow_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelSomebodyElseWorkflow_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelSomebodyElseWorkflow_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_CancelSomebodyElseWorkflow_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnOtherPoolAsAdmin_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnOtherPoolAsAdmin_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnOtherPoolAsAdmin_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnOtherPoolAsAdmin_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnOtherPool_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnOtherPool_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnOtherPool_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnOtherPool_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnReviewTask_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnReviewTask_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnReviewTask_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimOnReviewTask_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimReleaseWorkflowTaskOnPooledTask_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimReleaseWorkflowTaskOnPooledTask_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimReleaseWorkflowTaskOnPooledTask_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ClaimReleaseWorkflowTaskOnPooledTask_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIDontHaveAccessToAsAdmin_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIDontHaveAccessToAsAdmin_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIDontHaveAccessToAsAdmin_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIDontHaveAccessToAsAdmin_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIDontHaveAccessTo_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIDontHaveAccessTo_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIDontHaveAccessTo_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIDontHaveAccessTo_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIHaveAccessTo_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIHaveAccessTo_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIHaveAccessTo_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetTaskByIDIHaveAccessTo_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIDontHaveAccessToAsAdmin_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIDontHaveAccessToAsAdmin_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIDontHaveAccessToAsAdmin_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIDontHaveAccessToAsAdmin_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIDontHaveAccessTo_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIDontHaveAccessTo_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIDontHaveAccessTo_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIDontHaveAccessTo_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIHaveAccessTo_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIHaveAccessTo_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIHaveAccessTo_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_GetWorkflowByIDIHaveAccessTo_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ReleaseOnOtherClaimedTasksAsAdmin_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ReleaseOnOtherClaimedTasksAsAdmin_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ReleaseOnOtherClaimedTasksAsAdmin_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ReleaseOnOtherClaimedTasksAsAdmin_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ReleaseOnOtherClaimedTasks_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ReleaseOnOtherClaimedTasks_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ReleaseOnOtherClaimedTasks_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_ReleaseOnOtherClaimedTasks_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextAllTasks_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextAllTasks_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextAllTasks_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextAllTasks_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextMyPooledTasks_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextMyPooledTasks_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextMyPooledTasks_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextMyPooledTasks_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextMyTasks_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextMyTasks_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextMyTasks_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_SearchContextMyTasks_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionMyTask_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionMyTask_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionMyTask_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionMyTask_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionSomeoneElseTaskAsAdmin_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionSomeoneElseTaskAsAdmin_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionSomeoneElseTaskAsAdmin_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionSomeoneElseTaskAsAdmin_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionSomeoneElseTask_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionSomeoneElseTask_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionSomeoneElseTask_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_TransitionSomeoneElseTask_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateEmpty_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateEmpty_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateEmpty_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateEmpty_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateMixedProperties_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateMixedProperties_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateMixedProperties_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateMixedProperties_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateModifiableProperties_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateModifiableProperties_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateModifiableProperties_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateModifiableProperties_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateNull_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateNull_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateNull_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateNull_Test.java diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateUnmodifiableProperties_Test.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateUnmodifiableProperties_Test.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateUnmodifiableProperties_Test.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/workflow/methods/WorkflowService_UpdateUnmodifiableProperties_Test.java diff --git a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/AlfrescoServerInfo.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/AlfrescoServerInfo.java new file mode 100644 index 00000000..4952ed14 --- /dev/null +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/AlfrescoServerInfo.java @@ -0,0 +1,40 @@ +package eu.xenit.apix.util; + +import com.github.dynamicextensionsalfresco.osgi.OsgiService; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.service.descriptor.DescriptorService; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +@Service +@OsgiService +public class AlfrescoServerInfo { + // Part of Alfresco Private API + private final DescriptorService descriptorService; + private final DataSource dataSource; + private NodeDAO nodeDAO; + + public AlfrescoServerInfo(@Qualifier("descriptorComponent") DescriptorService descriptorServiceParam, + DataSource dataSourceParam, + NodeDAO nodeDAOParam) { + descriptorService = descriptorServiceParam; + dataSource = dataSourceParam; + nodeDAO = nodeDAOParam; + } + + public String getAlfrescoVersion() { + return descriptorService + .getServerDescriptor() + .getVersion(); + } + + public long getAlfTransactionIdDAO() { + return nodeDAO.getMaxTxnId(); + } +} diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/util/SolrAdminClient.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/SolrAdminClient.java similarity index 86% rename from apix-integrationtests/src/main/java/eu/xenit/apix/util/SolrAdminClient.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/SolrAdminClient.java index 677c6175..49852aee 100644 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/util/SolrAdminClient.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/SolrAdminClient.java @@ -12,9 +12,9 @@ public class SolrAdminClient { - private SwitchableApplicationContextFactory searchSubSystem; - private SolrAdminHTTPClient client; - private String baseUrl; + private final SwitchableApplicationContextFactory searchSubSystem; + private final String baseUrl; + private SolrAdminHTTPClient client = null; public SolrAdminClient(String baseUrl, SwitchableApplicationContextFactory searchSubSystem) { this.baseUrl = baseUrl; @@ -56,9 +56,11 @@ public JSONObject getSolrSummaryJson() throws JSONException { return object.getJSONObject("Summary"); } - public int getLastTransactionId() { + public long getLastTransactionId() { try { - return getSolrSummaryJson().getJSONObject("alfresco").getInt("Id for last TX in index"); + return getSolrSummaryJson() + .getJSONObject("alfresco") + .getLong("Id for last TX in index"); } catch (JSONException e) { e.printStackTrace(); return -1; diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/util/SolrTestHelper.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/SolrTestHelper.java similarity index 100% rename from apix-integrationtests/src/main/java/eu/xenit/apix/util/SolrTestHelper.java rename to apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/SolrTestHelper.java diff --git a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java new file mode 100644 index 00000000..7404cc57 --- /dev/null +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java @@ -0,0 +1,140 @@ +package eu.xenit.apix.util; + +import java.util.Properties; +import java.util.function.Supplier; + +import com.github.dynamicextensionsalfresco.osgi.OsgiService; +import org.alfresco.repo.management.subsystems.SwitchableApplicationContextFactory; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +/** + * This class should only be used by the integration tests. + */ +@Service +@OsgiService +public class SolrTestHelperImpl implements SolrTestHelper { + private static final Logger logger = LoggerFactory.getLogger(SolrTestHelperImpl.class); + + private static final String SOLR_SUMMARY_CORE_ALFRESCO = "alfresco"; + private static final String SOLR_SUMMARY_FTS = "FTS"; + private static final String SOLR_SUMMARY_FTS_DIRTY = "Node count whose content needs to be updated"; + private static final String SOLR_SUMMARY_FTS_CLEAN = "Node count whose content is in sync"; + private static final String SOLR_SUMMARY_FTS_NEW_6 = "Node count with FTSStatus New"; + private static final String SOLR_SUMMARY_FTS_DIRTY_6 = "Node count with FTSStatus Dirty"; + private static final String SOLR_SUMMARY_FTS_CLEAN_6 = "Node count with FTSStatus Clean"; + + private final AlfrescoServerInfo alfrescoServerInfo; + protected SolrAdminClient solrAdminClient; + + private static final int MAX_ATTEMPTS = 20; + + public SolrTestHelperImpl( + @Qualifier("global-properties") Properties globalProperties, + @Qualifier("Search") SwitchableApplicationContextFactory searchSubSystem, + + AlfrescoServerInfo alfrescoServerInfoParam) { + String subsystem = globalProperties.getProperty("index.subsystem.name"); + String solrBaseUrl = subsystem.equals("solr4") ? "/solr4" : "/solr"; + alfrescoServerInfo = alfrescoServerInfoParam; + solrAdminClient = new SolrAdminClient(solrBaseUrl, searchSubSystem); + } + + /** + * Beware of calling this method too frequently since it runs an aggregate query over the entire alf_nodes table + * + * @return true if the latest Alfresco transaction has been indexed by Solr + */ + @Override + public boolean areTransactionsSynced() { + long alfTransaction = alfrescoServerInfo.getAlfTransactionIdDAO(); + long solrTransaction = solrAdminClient.getLastTransactionId(); + logger.debug("alf transaction: {}, solr transaction: {}", alfTransaction, solrTransaction); + return alfTransaction <= solrTransaction; + } + + /** + * Wait until Solr has indexed the latest Alfresco transaction. + */ + @Override + public void waitForTransactionSync() throws InterruptedException { + waitForCompletion(this::areTransactionsSynced); + } + + @Override + public int getNumberOfFtsStatusCleanDocs() { + return (Integer) getSummaryFtsSection().get( + isAlfresco61() ? SOLR_SUMMARY_FTS_CLEAN_6 : SOLR_SUMMARY_FTS_CLEAN + ); + } + + @Override + public boolean isContentIndexed() { + return isContentIndexedImpl(null); + } + + @Override + public boolean isContentIndexed(int previousCleanCount) { + logger.debug("previousCleanCount: {}", previousCleanCount); + return isContentIndexedImpl(previousCleanCount); + } + + @Override + public void waitForContentSync() throws InterruptedException { + waitForCompletion(() -> isContentIndexedImpl(null)); + } + + @Override + public void waitForContentSync(int previousCleanCount) throws InterruptedException { + logger.debug("previousCleanCount: {}", previousCleanCount); + waitForCompletion(() -> isContentIndexedImpl(previousCleanCount)); + } + + protected JSONObject getSummaryFtsSection() { + return solrAdminClient + .getSolrSummaryJson() + .getJSONObject(SOLR_SUMMARY_CORE_ALFRESCO) + .getJSONObject(SOLR_SUMMARY_FTS); + } + + private void waitForCompletion(Supplier hasCompleted) throws InterruptedException { + System.out.print("Waiting 5 seconds for Solr to index content"); + for (int i = 0; i < MAX_ATTEMPTS; i++) { + if (hasCompleted.get()) { + return; + } + for (int j = 0; j < 5; j++) { + System.out.print("..." + ((i * 5) + j + 1)); + Thread.sleep(1000); + } + System.out.println(); + } + } + + private boolean isContentIndexedImpl(Integer previousCleanCount) { + JSONObject ftsBlock = getSummaryFtsSection(); + logger.debug("solrSummaryFTSBlock: {}", ftsBlock.toString(4)); + if(isAlfresco61()) { + return 0 == ((Integer) ftsBlock.get(SOLR_SUMMARY_FTS_NEW_6)) + && 0 == (Integer) ftsBlock.get(SOLR_SUMMARY_FTS_DIRTY_6) + && checkPreviousCount(previousCleanCount, (Integer) ftsBlock.get(SOLR_SUMMARY_FTS_CLEAN_6)); + } + return 0 == (Integer) ftsBlock.get(SOLR_SUMMARY_FTS_DIRTY) + && checkPreviousCount(previousCleanCount, (Integer) ftsBlock.get(SOLR_SUMMARY_FTS_CLEAN)); + } + + private boolean isAlfresco61() { + logger.debug("Alfresco version: {}", alfrescoServerInfo.getAlfrescoVersion()); + return alfrescoServerInfo.getAlfrescoVersion().startsWith("6.1"); + } + + private boolean checkPreviousCount(Integer previousCleanCount, Integer solrSummaryFtsCount) { + if(previousCleanCount == null) { + return true; // no need to check + } + return previousCleanCount < solrSummaryFtsCount; + } +} diff --git a/apix-integrationtests/src/main/resources/cyrillic_message.msg b/apix-integrationtests/alfresco/src/main/resources/cyrillic_message.msg similarity index 100% rename from apix-integrationtests/src/main/resources/cyrillic_message.msg rename to apix-integrationtests/alfresco/src/main/resources/cyrillic_message.msg diff --git a/apix-integrationtests/src/main/resources/facet-forms-config.json b/apix-integrationtests/alfresco/src/main/resources/facet-forms-config.json similarity index 100% rename from apix-integrationtests/src/main/resources/facet-forms-config.json rename to apix-integrationtests/alfresco/src/main/resources/facet-forms-config.json diff --git a/apix-integrationtests/alfresco/src/test/java/eu/xenit/apix/util/AlfrescoServerInfoTest.java b/apix-integrationtests/alfresco/src/test/java/eu/xenit/apix/util/AlfrescoServerInfoTest.java new file mode 100644 index 00000000..9b0a151e --- /dev/null +++ b/apix-integrationtests/alfresco/src/test/java/eu/xenit/apix/util/AlfrescoServerInfoTest.java @@ -0,0 +1,22 @@ +package eu.xenit.apix.util; + +import org.alfresco.service.descriptor.Descriptor; +import org.alfresco.service.descriptor.DescriptorService; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +public class AlfrescoServerInfoTest { + @Test + public void testVersionLowerThan6x() { + DescriptorService descriptorService = mock(DescriptorService.class); + Descriptor descriptor = mock(Descriptor.class); + doReturn("6.1.1 (3 rc25a8127-b23)").when(descriptor).getVersion(); + doReturn(descriptor).when(descriptorService).getServerDescriptor(); + AlfrescoServerInfo asi = new AlfrescoServerInfo(descriptorService, null); + String version = asi.getAlfrescoVersion(); + assertTrue(version.startsWith("6.")); + } +} diff --git a/apix-integrationtests-model-amp/README.md b/apix-integrationtests/model-amp/README.md similarity index 100% rename from apix-integrationtests-model-amp/README.md rename to apix-integrationtests/model-amp/README.md diff --git a/apix-integrationtests-model-amp/build.gradle b/apix-integrationtests/model-amp/build.gradle similarity index 100% rename from apix-integrationtests-model-amp/build.gradle rename to apix-integrationtests/model-amp/build.gradle diff --git a/apix-integrationtests-model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/messages/apixtest.properties b/apix-integrationtests/model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/messages/apixtest.properties similarity index 100% rename from apix-integrationtests-model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/messages/apixtest.properties rename to apix-integrationtests/model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/messages/apixtest.properties diff --git a/apix-integrationtests-model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/messages/apixtest_nl.properties b/apix-integrationtests/model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/messages/apixtest_nl.properties similarity index 100% rename from apix-integrationtests-model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/messages/apixtest_nl.properties rename to apix-integrationtests/model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/messages/apixtest_nl.properties diff --git a/apix-integrationtests-model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/model/apixtest-model.xml b/apix-integrationtests/model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/model/apixtest-model.xml similarity index 100% rename from apix-integrationtests-model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/model/apixtest-model.xml rename to apix-integrationtests/model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/model/apixtest-model.xml diff --git a/apix-integrationtests-model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/module-context.xml b/apix-integrationtests/model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/module-context.xml similarity index 100% rename from apix-integrationtests-model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/module-context.xml rename to apix-integrationtests/model-amp/src/main/amp/config/alfresco/module/apix-integrationtests-model-amp/module-context.xml diff --git a/apix-integrationtests/src/main/java/eu/xenit/apix/util/SolrTestHelperBaseImpl.java b/apix-integrationtests/src/main/java/eu/xenit/apix/util/SolrTestHelperBaseImpl.java deleted file mode 100644 index 0b62e43e..00000000 --- a/apix-integrationtests/src/main/java/eu/xenit/apix/util/SolrTestHelperBaseImpl.java +++ /dev/null @@ -1,136 +0,0 @@ -package eu.xenit.apix.util; - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import javax.sql.DataSource; -import org.alfresco.repo.management.subsystems.SwitchableApplicationContextFactory; -import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class should only be used by the integration tests. - */ -public abstract class SolrTestHelperBaseImpl implements SolrTestHelper { - private Logger logger = LoggerFactory.getLogger(SolrTestHelperBaseImpl.class); - - protected final String SOLR_SUMMARY_CORE_ALFRESCO = "alfresco"; - protected final String SOLR_SUMMARY_FTS = "FTS"; - protected final String SOLR_SUMMARY_FTS_DIRTY = "Node count whose content needs to be updated"; - protected final String SOLR_SUMMARY_FTS_CLEAN = "Node count whose content is in sync"; - - private DataSource dataSource; - protected SolrAdminClient solrAdminClient; - - private int maxTries = 20; - - public SolrTestHelperBaseImpl(String baseUrl, DataSource dataSource, SwitchableApplicationContextFactory searchSubSystem) { - this.dataSource = dataSource; - solrAdminClient = new SolrAdminClient(baseUrl, searchSubSystem); - } - - /** - * Beware of calling this method too frequently since it runs an aggregate query over the entire alf_nodes table - * - * @return true if the latest Alfresco transaction has been indexed by Solr - */ - @Override - public boolean areTransactionsSynced() { - int alfTransaction = getAlfTransactionId(); - int solrTransaction = solrAdminClient.getLastTransactionId(); - logger.debug("alf transaction: {}, solr transaction: {}", alfTransaction, solrTransaction); - return alfTransaction <= solrTransaction; - } - - /** - * Wait until Solr has indexed the latest Alfresco transaction. - */ - @Override - public void waitForTransactionSync() throws InterruptedException { - for (int i = 0; i < maxTries; i++) { - if (areTransactionsSynced()) { - return; - } - // These prints are here to send data over the wire while waiting. - // This prevents any http proxy from closing the connection due to timeouts - System.out.print("Waiting 5 seconds for Solr to index transactions"); - for (int j = 0; j < 5; j++) { - System.out.print("..." + ((i * 5) + j + 1)); - Thread.sleep(1000); - } - System.out.println(); - } - } - - @Override - public int getNumberOfFtsStatusCleanDocs() { - return (Integer) getSummaryFtsSection().get(SOLR_SUMMARY_FTS_CLEAN); - } - - @Override - public boolean isContentIndexed() { - JSONObject ftsBlock = getSummaryFtsSection(); - logger.debug("solrSummaryFTSBlock: {}", ftsBlock.toString(4)); - return 0 == (Integer) ftsBlock.get(SOLR_SUMMARY_FTS_DIRTY); - } - - @Override - public boolean isContentIndexed(int previousCleanCount) { - JSONObject ftsBlock = getSummaryFtsSection(); - logger.debug("solrSummaryFTSBlock: {}", ftsBlock.toString(4)); - return 0 == (Integer) ftsBlock.get(SOLR_SUMMARY_FTS_DIRTY) - && previousCleanCount < ((Integer) ftsBlock.get(SOLR_SUMMARY_FTS_CLEAN)); - } - - @Override - public void waitForContentSync() throws InterruptedException { - for (int i = 0; i < maxTries; i++) { - if (isContentIndexed()) { - return; - } - System.out.print("Waiting 5 seconds for Solr to index content"); - for (int j = 0; j < 5; j++) { - System.out.print("..." + ((i * 5) + j + 1)); - Thread.sleep(1000); - } - System.out.println(); - } - } - - @Override - public void waitForContentSync(int previousCleanCount) throws InterruptedException { - logger.debug("previousCleanCount: {}", previousCleanCount); - for (int i = 0; i < maxTries; i++) { - if (isContentIndexed(previousCleanCount)) { - return; - } - System.out.print("Waiting 5 seconds for Solr to index content"); - for (int j = 0; j < 5; j++) { - System.out.print("..." + ((i * 5) + j + 1)); - Thread.sleep(1000); - } - System.out.println(); - } - } - - private int getAlfTransactionId() { - try (Connection connection = dataSource.getConnection()) { - final Statement stmt = connection.createStatement(); - final ResultSet rs = stmt.executeQuery("select max( transaction_id ) from alf_node"); - - if (rs.next()) { - return rs.getInt(1); - } - rs.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return -1; - } - - protected JSONObject getSummaryFtsSection() { - return solrAdminClient.getSolrSummaryJson().getJSONObject(SOLR_SUMMARY_CORE_ALFRESCO).getJSONObject(SOLR_SUMMARY_FTS); - } -} diff --git a/apix-rest-v1/build.gradle b/apix-rest-v1/build.gradle index 39d5ea0c..e7b89619 100644 --- a/apix-rest-v1/build.gradle +++ b/apix-rest-v1/build.gradle @@ -15,8 +15,10 @@ artifacts { ampArtifact amp } +apply from: "$rootProject.projectDir/alfresco/70/overrides.gradle" + dependencies { - implementation platform("org.alfresco:acs-community-packaging:$alfrescoVersion") + implementation platform("org.alfresco:acs-community-packaging:$alfresco_version") // implementation "org.springframework.boot:spring-boot-starter-parent:2.6.6" // implementation "org.springframework.boot:spring-boot-starter-actuator:2.6.6" //// implementation "org.springframework.boot:spring-boot-starter-integration:2.6.6" @@ -50,7 +52,7 @@ dependencies { testImplementation project(':apix-interface') testImplementation project(':apix-impl') - testImplementation platform("org.alfresco:acs-community-packaging:$alfrescoVersion") + testImplementation platform("org.alfresco:acs-community-packaging:$alfresco_version") testImplementation 'org.springframework:spring-core' testImplementation 'org.springframework:spring-test' testImplementation "org.alfresco.surf:spring-webscripts" diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/SpringConfig.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/SpringConfig.java index b2a68b9e..44cefd38 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/SpringConfig.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/SpringConfig.java @@ -5,7 +5,7 @@ @EnableAlfrescoMvcRest( @AlfrescoDispatcherWebscript( - name = "alfred-rest.api", + name = "alfred.api", servletContext = AlfredApiRestServletContext.class ) ) diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateResponse.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateResponse.java index 80ec79b8..478c62d5 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateResponse.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateResponse.java @@ -65,7 +65,6 @@ public void reset() { // not supported } - @Override public void reset(String preserveHeadersPattern) { // not supported } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java index 55a2f8f4..1b4e45ac 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java @@ -622,7 +622,7 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions }, false, true); if (resultObject == null) { - return ResponseEntity.internalServerError().build(); + return ResponseEntity.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).build(); } NodeRef resultRef = new NodeRef(resultObject.toString()); diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.delete.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.delete.desc.xml similarity index 100% rename from apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.delete.desc.xml rename to apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.delete.desc.xml diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.get.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.get.desc.xml similarity index 100% rename from apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.get.desc.xml rename to apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.get.desc.xml diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.post.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.post.desc.xml similarity index 100% rename from apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.post.desc.xml rename to apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.post.desc.xml diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.put.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.put.desc.xml similarity index 100% rename from apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred-rest/api.put.desc.xml rename to apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.put.desc.xml diff --git a/build.gradle b/build.gradle index 7e127bd2..ee034990 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,14 @@ +plugins { + // Centralize plugin version management + id 'be.vbgn.ci-detect' version '0.5.0' apply false + id 'eu.xenit.de' version '2.1.3' apply false + id 'eu.xenit.amp' version '1.1.0' apply false + id 'eu.xenit.alfresco' version '1.1.0' apply false + id 'eu.xenit.docker-alfresco' version '5.3.1' apply false + id 'eu.xenit.docker-compose' version '5.3.1' apply false + id 'eu.xenit.alfresco-remote-testrunner' version '2.0.0' apply false +} + def static getVersionQualifier(String branch_name) { if(branch_name.startsWith('release')) return '' @@ -8,33 +19,12 @@ def static getVersionQualifier(String branch_name) { ext { versionWithoutQualifier = '4.0.0' - + de_version = "2.1.3" + mvc = "8.0.0" jackson_version = '2.8.3' swagger_version = "1.5.7" // 2.2.4 - - http_core_version = "4.3.3" - http_version = "4.3.4" - - alfresco_61_version = "6.1" - alfresco_62_version = "6.2" - alfresco_70_version = "7.0" - alfresco_71_version = "7.1" - alfresco_72_version = "7.2" - alfresco_73_version = "7.3" - - // alfresco-data-model might have a different version number than the main war it's included in - // ref: https://bitbucket.org/xenit/alfresco-bom/src/master/repo/eu/xenit/alfresco/ for the bom of vanilla alfresco - alfresco_61_dm_version = "8.25.1" - alfresco_62_dm_version = "8.50.18" - alfresco_70_dm_version = "8.424" - alfresco_71_dm_version = "12.23" - alfresco_72_dm_version = "14.142" - alfresco_73_dm_version = "17.175" - care4alfVersion = '2.3.0' - - mvc = "8.0.0" - alfrescoVersion = "7.2.0" + http_version = "4.3.4" // Used by integration tests } subprojects { diff --git a/settings.gradle b/settings.gradle index fb6affdf..26d46d3b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,41 +2,20 @@ rootProject.name = 'apix' include ':apix-interface' include ':apix-rest-v1' - include ':apix-impl' -include ':apix-impl:apix-impl-62' -include ':apix-impl:apix-impl-70' -include ':apix-impl:apix-impl-71' -include ':apix-impl:apix-impl-72' -include ':apix-impl:apix-impl-73' - include ':apix-docker' -include ':apix-docker:docker-62' -include ':apix-docker:docker-70' -include ':apix-docker:docker-71' -include ':apix-docker:docker-72' -include ':apix-docker:docker-73' - include ':apix-integrationtests' -include ':apix-integrationtests:test-62' -include ':apix-integrationtests:test-70' -include ':apix-integrationtests:test-71' -include ':apix-integrationtests:test-72' -include ':apix-integrationtests:test-73' -include ':apix-integrationtests-model-amp' +include ':apix-integrationtests:model-amp' + +ext { + versions = ["6.1", "6.2", "7.0", "7.1", "7.2", "7.3"] +} -project(':apix-impl:apix-impl-62').projectDir = "$rootDir/apix-impl/62" as File -project(':apix-impl:apix-impl-70').projectDir = "$rootDir/apix-impl/70" as File -project(':apix-impl:apix-impl-71').projectDir = "$rootDir/apix-impl/71" as File -project(':apix-impl:apix-impl-72').projectDir = "$rootDir/apix-impl/72" as File -project(':apix-impl:apix-impl-73').projectDir = "$rootDir/apix-impl/73" as File -project(':apix-docker:docker-62').projectDir = "$rootDir/apix-docker/62" as File -project(':apix-docker:docker-70').projectDir = "$rootDir/apix-docker/70" as File -project(':apix-docker:docker-71').projectDir = "$rootDir/apix-docker/71" as File -project(':apix-docker:docker-72').projectDir = "$rootDir/apix-docker/72" as File -project(':apix-docker:docker-73').projectDir = "$rootDir/apix-docker/73" as File -project(':apix-integrationtests:test-62').projectDir = "$rootDir/apix-integrationtests/62" as File -project(':apix-integrationtests:test-70').projectDir = "$rootDir/apix-integrationtests/70" as File -project(':apix-integrationtests:test-71').projectDir = "$rootDir/apix-integrationtests/71" as File -project(':apix-integrationtests:test-72').projectDir = "$rootDir/apix-integrationtests/72" as File -project(':apix-integrationtests:test-73').projectDir = "$rootDir/apix-integrationtests/73" as File +for(String version : versions) { + def shortVersion = version.replaceAll("\\.","") + include ":apix-impl:apix-impl-$shortVersion" + include ":apix-docker:docker-$shortVersion" + include ":apix-integrationtests:alfresco:$shortVersion" + project(":apix-impl:apix-impl-$shortVersion").projectDir = "$rootDir/apix-impl/$shortVersion" as File + project(":apix-docker:docker-$shortVersion").projectDir = "$rootDir/apix-docker/$shortVersion" as File +} \ No newline at end of file From be39843732b436218122ae95a6e84a649f9e80c8 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Thu, 3 Nov 2022 23:05:06 +0200 Subject: [PATCH 18/90] ALFREDAPI-504 Drop Java 8 backports --- .../apix/alfresco/search/SearchService.java | 2 +- .../eu/xenit/apix/search/QueryBuilder.java | 48 +-- .../eu/xenit/apix/utils/java8/Consumer.java | 16 - .../eu/xenit/apix/utils/java8/Function.java | 8 - .../eu/xenit/apix/utils/java8/Optional.java | 284 ------------------ .../eu/xenit/apix/utils/java8/Predicate.java | 8 - .../eu/xenit/apix/utils/java8/Supplier.java | 8 - 7 files changed, 16 insertions(+), 358 deletions(-) delete mode 100644 apix-interface/src/main/java/eu/xenit/apix/utils/java8/Consumer.java delete mode 100644 apix-interface/src/main/java/eu/xenit/apix/utils/java8/Function.java delete mode 100644 apix-interface/src/main/java/eu/xenit/apix/utils/java8/Optional.java delete mode 100644 apix-interface/src/main/java/eu/xenit/apix/utils/java8/Predicate.java delete mode 100644 apix-interface/src/main/java/eu/xenit/apix/utils/java8/Supplier.java diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/search/SearchService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/search/SearchService.java index f0890d98..fcc7e517 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/search/SearchService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/search/SearchService.java @@ -11,10 +11,10 @@ import eu.xenit.apix.search.SearchQuery.HighlightOptions; import eu.xenit.apix.search.SearchQueryConsistency; import eu.xenit.apix.search.SearchQueryResult; -import eu.xenit.apix.utils.java8.Optional; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.FieldHighlightParameters; diff --git a/apix-interface/src/main/java/eu/xenit/apix/search/QueryBuilder.java b/apix-interface/src/main/java/eu/xenit/apix/search/QueryBuilder.java index e0d2fda7..888a8879 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/search/QueryBuilder.java +++ b/apix-interface/src/main/java/eu/xenit/apix/search/QueryBuilder.java @@ -1,9 +1,14 @@ package eu.xenit.apix.search; -import eu.xenit.apix.search.nodes.*; -import eu.xenit.apix.utils.java8.Consumer; +import eu.xenit.apix.search.nodes.InvertSearchNode; +import eu.xenit.apix.search.nodes.OperatorSearchNode; +import eu.xenit.apix.search.nodes.PropertySearchNode; +import eu.xenit.apix.search.nodes.RangeValue; +import eu.xenit.apix.search.nodes.SearchSyntaxNode; +import eu.xenit.apix.search.nodes.TermSearchNode; import java.util.ArrayList; +import java.util.function.Consumer; /** * Object used to build a search query. @@ -19,16 +24,9 @@ public class QueryBuilder { SearchSyntaxNode result = null; public QueryBuilder() { -// acceptNode = x -> { -// result = x; -// acceptNode = null; -// }; - acceptNode = new Consumer() { - @Override - public void accept(SearchSyntaxNode searchSyntaxNode) { - result = searchSyntaxNode; - acceptNode = null; - } + acceptNode = searchSyntaxNode -> { + result = searchSyntaxNode; + acceptNode = null; }; } @@ -108,17 +106,11 @@ public QueryBuilder startAnd() { } private QueryBuilder startOperator(OperatorSearchNode.Operator operator) { - final OperatorSearchNode node = new OperatorSearchNode(operator, new ArrayList()); + final OperatorSearchNode node = new OperatorSearchNode(operator, new ArrayList<>()); QueryBuilder subBuilder = new QueryBuilder(); subBuilder.result = node; -// subBuilder.acceptNode = x -> node.getChildren().add(x); - subBuilder.acceptNode = new Consumer() { - @Override - public void accept(SearchSyntaxNode searchSyntaxNode) { - node.getChildren().add(searchSyntaxNode); - } - }; + subBuilder.acceptNode = searchSyntaxNode -> node.getChildren().add(searchSyntaxNode); subBuilder.parent = this; return subBuilder; @@ -153,19 +145,9 @@ public QueryBuilder not() { final Consumer oldAccept = acceptNode; -// acceptNode = x -> { -// // This has to be before accept, non-elegant solution, because the result-accept sets acceptNode to 0 -// acceptNode = oldAccept; -// oldAccept.accept(new InvertSearchNode(x)); -// -// }; - - acceptNode = new Consumer() { - @Override - public void accept(SearchSyntaxNode searchSyntaxNode) { - acceptNode = oldAccept; - oldAccept.accept(new InvertSearchNode(searchSyntaxNode)); - } + acceptNode = searchSyntaxNode -> { + acceptNode = oldAccept; + oldAccept.accept(new InvertSearchNode(searchSyntaxNode)); }; return this; diff --git a/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Consumer.java b/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Consumer.java deleted file mode 100644 index 1788597b..00000000 --- a/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Consumer.java +++ /dev/null @@ -1,16 +0,0 @@ -package eu.xenit.apix.utils.java8; - -/** - * Copy of the java 8 comsumer interface - */ -public interface Consumer { - - /** - * Performs this operation on the given argument. - * - * @param t the input argument - */ - void accept(T t); - - -} diff --git a/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Function.java b/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Function.java deleted file mode 100644 index 94a07c3e..00000000 --- a/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Function.java +++ /dev/null @@ -1,8 +0,0 @@ -package eu.xenit.apix.utils.java8; - -/** - */ -public interface Function { - - R apply(T t); -} diff --git a/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Optional.java b/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Optional.java deleted file mode 100644 index c008efef..00000000 --- a/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Optional.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - */ -package eu.xenit.apix.utils.java8; - -import java.util.NoSuchElementException; -import java.util.Objects; - -/** - * Port to java 7 - */ -public final class Optional { - - /** - * Common instance for {@code empty()}. - */ - private static final Optional EMPTY = new Optional<>(); - - /** - * If non-null, the value; if null, indicates no value is present - */ - private final T value; - - /** - * Constructs an empty instance. - * - * Generally only one empty instance, {@link Optional#EMPTY}, should exist per VM. - */ - private Optional() { - this.value = null; - } - - /** - * Constructs an instance with the value present. - * - * @param value the non-null value to be present - * @throws NullPointerException if value is null - */ - private Optional(T value) { - this.value = Objects.requireNonNull(value); - } - - /** - * Returns an empty {@code Optional} instance. No value is present for this Optional. - * - * Though it may be tempting to do so, avoid testing if an object is empty by comparing with {@code ==} against - * instances returned by {@code Option.empty()}. There is no guarantee that it is a singleton. Instead, use {@link - * #isPresent()}. - * - * @param Type of the non-existent value - * @return an empty {@code Optional} - */ - public static Optional empty() { - @SuppressWarnings("unchecked") - Optional t = (Optional) EMPTY; - return t; - } - - /** - * Returns an {@code Optional} with the specified present non-null value. - * - * @param the class of the value - * @param value the value to be present, which must be non-null - * @return an {@code Optional} with the value present - * @throws NullPointerException if value is null - */ - public static Optional of(T value) { - return new Optional<>(value); - } - - /** - * Returns an {@code Optional} describing the specified value, if non-null, otherwise returns an empty {@code - * Optional}. - * - * @param the class of the value - * @param value the possibly-null value to describe - * @return an {@code Optional} with a present value if the specified value is non-null, otherwise an empty {@code - * Optional} - */ - public static Optional ofNullable(T value) { - return value == null ? (Optional) empty() : of(value); - } - - /** - * If a value is present in this {@code Optional}, returns the value, otherwise throws {@code - * NoSuchElementException}. - * - * @return the non-null value held by this {@code Optional} - * @throws NoSuchElementException if there is no value present - * @see Optional#isPresent() - */ - public T get() { - if (value == null) { - throw new NoSuchElementException("No value present"); - } - return value; - } - - /** - * Return {@code true} if there is a value present, otherwise {@code false}. - * - * @return {@code true} if there is a value present, otherwise {@code false} - */ - public boolean isPresent() { - return value != null; - } - - /** - * If a value is present, invoke the specified consumer with the value, otherwise do nothing. - * - * @param consumer block to be executed if a value is present - * @throws NullPointerException if value is present and {@code consumer} is null - */ - public void ifPresent(Consumer consumer) { - if (value != null) { - consumer.accept(value); - } - } - - /** - * If a value is present, and the value matches the given predicate, return an {@code Optional} describing the - * value, otherwise return an empty {@code Optional}. - * - * @param predicate a predicate to apply to the value, if present - * @return an {@code Optional} describing the value of this {@code Optional} if a value is present and the value - * matches the given predicate, otherwise an empty {@code Optional} - * @throws NullPointerException if the predicate is null - */ - public Optional filter(Predicate predicate) { - Objects.requireNonNull(predicate); - if (!isPresent()) { - return this; - } else { - return predicate.test(value) ? this : (Optional) empty(); - } - } - - /** - * If a value is present, apply the provided mapping function to it, and if the result is non-null, return an {@code - * Optional} describing the result. Otherwise return an empty {@code Optional}. - * - * This method supports post-processing on optional values, without the need to explicitly check for a return - * status. For example, the following code traverses a stream of file names, selects one that has not yet been - * processed, and then opens that file, returning an {@code Optional}: - * - *
{@code
-     *     Optional fis =
-     *         names.stream().filter(name -> !isProcessedYet(name))
-     *                       .findFirst()
-     *                       .map(name -> new FileInputStream(name));
-     * }
- * - * Here, {@code findFirst} returns an {@code Optional}, and then {@code map} returns an {@code - * Optional} for the desired file if one exists. - * - * @param The type of the result of the mapping function - * @param mapper a mapping function to apply to the value, if present - * @return an {@code Optional} describing the result of applying a mapping function to the value of this {@code - * Optional}, if a value is present, otherwise an empty {@code Optional} - * @throws NullPointerException if the mapping function is null - */ - public Optional map(Function mapper) { - Objects.requireNonNull(mapper); - if (!isPresent()) { - return empty(); - } else { - return (Optional) Optional.ofNullable(mapper.apply(value)); - } - } - - /** - * If a value is present, apply the provided {@code Optional}-bearing mapping function to it, return that result, - * otherwise return an empty {@code Optional}. This method is similar to {@link #map(Function)}, but the provided - * mapper is one whose result is already an {@code Optional}, and if invoked, {@code flatMap} does not wrap it with - * an additional {@code Optional}. - * - * @param The type parameter to the {@code Optional} returned by - * @param mapper a mapping function to apply to the value, if present the mapping function - * @return the result of applying an {@code Optional}-bearing mapping function to the value of this {@code - * Optional}, if a value is present, otherwise an empty {@code Optional} - * @throws NullPointerException if the mapping function is null or returns a null result - */ - public Optional flatMap(Function> mapper) { - Objects.requireNonNull(mapper); - if (!isPresent()) { - return empty(); - } else { - return Objects.requireNonNull(mapper.apply(value)); - } - } - - /** - * Return the value if present, otherwise return {@code other}. - * - * @param other the value to be returned if there is no value present, may be null - * @return the value, if present, otherwise {@code other} - */ - public T orElse(T other) { - return value != null ? value : other; - } - - /** - * Return the value if present, otherwise invoke {@code other} and return the result of that invocation. - * - * @param other a {@code Supplier} whose result is returned if no value is present - * @return the value if present otherwise the result of {@code other.get()} - * @throws NullPointerException if value is not present and {@code other} is null - */ - public T orElseGet(Supplier other) { - return value != null ? value : other.get(); - } - - /** - * Return the contained value, if present, otherwise throw an exception to be created by the provided supplier. - * - * A method reference to the exception constructor with an empty argument list can be used as the supplier. For - * example, {@code IllegalStateException::new} - * - * @param Type of the exception to be thrown - * @param exceptionSupplier The supplier which will return the exception to be thrown - * @return the present value - * @throws X if there is no value present - * @throws NullPointerException if no value is present and {@code exceptionSupplier} is null - */ - public T orElseThrow(Supplier exceptionSupplier) throws X { - if (value != null) { - return value; - } else { - throw exceptionSupplier.get(); - } - } - - /** - * Indicates whether some other object is "equal to" this Optional. The other object is considered equal if: - *
    - *
  • it is also an {@code Optional} and; - *
  • both instances have no value present or; - *
  • the present values are "equal to" each other via {@code equals()}. - *
- * - * @param obj an object to be tested for equality - * @return {code true} if the other object is "equal to" this object otherwise {@code false} - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (!(obj instanceof Optional)) { - return false; - } - - Optional other = (Optional) obj; - return Objects.equals(value, other.value); - } - - /** - * Returns the hash code value of the present value, if any, or 0 (zero) if no value is present. - * - * @return hash code value of the present value or 0 if no value is present - */ - @Override - public int hashCode() { - return Objects.hashCode(value); - } - - /** - * Returns a non-empty string representation of this Optional suitable for debugging. The exact presentation format - * is unspecified and may vary between implementations and versions. - * - * If a value is present the result must include its string representation in the result. Empty and present - * Optionals must be unambiguously differentiable. - * - * @return the string representation of this instance - */ - @Override - public java.lang.String toString() { - return value != null - ? java.lang.String.format("Optional[%s]", value) - : "Optional.empty"; - } -} diff --git a/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Predicate.java b/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Predicate.java deleted file mode 100644 index da04eb95..00000000 --- a/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Predicate.java +++ /dev/null @@ -1,8 +0,0 @@ -package eu.xenit.apix.utils.java8; - -/** - */ -public interface Predicate { - - boolean test(T t); -} diff --git a/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Supplier.java b/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Supplier.java deleted file mode 100644 index 75302151..00000000 --- a/apix-interface/src/main/java/eu/xenit/apix/utils/java8/Supplier.java +++ /dev/null @@ -1,8 +0,0 @@ -package eu.xenit.apix.utils.java8; - -/** - */ -public interface Supplier { - - T get(); -} From d5f3e61e5eb84ffdfa6be3929ed146488e4d9a9f Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Fri, 4 Nov 2022 09:07:41 +0200 Subject: [PATCH 19/90] ALFREDAPI-504 Amp 7.2 max version fix --- alfresco/72/overrides.gradle | 4 +--- apix-impl/build.gradle | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/alfresco/72/overrides.gradle b/alfresco/72/overrides.gradle index 7a69687c..81fc98a4 100644 --- a/alfresco/72/overrides.gradle +++ b/alfresco/72/overrides.gradle @@ -1,7 +1,5 @@ ext { alfresco_version = "7.2.1" alfresco_min_version = alfresco_version.substring(0, 3) + ".0" + alfresco_max_version = null } -if(project.hasProperty("alfresco_max_version")) { - project.properties.remove("alfresco_max_version") -} \ No newline at end of file diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index 88fd37d6..0a2786f8 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -40,7 +40,8 @@ subprojects { "Xenit API-X implementation Alfresco ${alfresco_version.substring(0, 3)}") it.put("module.version", project.version) it.put("module.repo.version.min", project.alfresco_min_version) - if(project.hasProperty("alfresco_max_version")) { + if(project.hasProperty("alfresco_max_version") + && project.alfresco_max_version != null) { it.put("module.repo.version.max", project.alfresco_max_version) } } From a57bcfd49b3aedc6ce346b76366a98bda2c5f9c6 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Fri, 4 Nov 2022 10:23:29 +0200 Subject: [PATCH 20/90] ALFREDAPI-504 Cleanup --- .../java/eu/xenit/apix/util/AlfrescoServerInfo.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/AlfrescoServerInfo.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/AlfrescoServerInfo.java index 4952ed14..4db41541 100644 --- a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/AlfrescoServerInfo.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/AlfrescoServerInfo.java @@ -6,25 +6,16 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - @Service @OsgiService public class AlfrescoServerInfo { // Part of Alfresco Private API private final DescriptorService descriptorService; - private final DataSource dataSource; - private NodeDAO nodeDAO; + private final NodeDAO nodeDAO; public AlfrescoServerInfo(@Qualifier("descriptorComponent") DescriptorService descriptorServiceParam, - DataSource dataSourceParam, NodeDAO nodeDAOParam) { descriptorService = descriptorServiceParam; - dataSource = dataSourceParam; nodeDAO = nodeDAOParam; } From 40b2465241bae6656acfed45e2713916060d38ee Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Fri, 4 Nov 2022 10:23:40 +0200 Subject: [PATCH 21/90] ALFREDAPI-504 Docker correct configuration --- apix-docker/62/docker-compose.yml | 4 ++++ apix-docker/70/docker-compose.yml | 6 ++++++ apix-docker/71/docker-compose.yml | 6 ++++++ apix-docker/72/docker-compose.yml | 6 ++++++ apix-docker/build.gradle | 20 -------------------- 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/apix-docker/62/docker-compose.yml b/apix-docker/62/docker-compose.yml index 3c09b18e..8ad360d7 100644 --- a/apix-docker/62/docker-compose.yml +++ b/apix-docker/62/docker-compose.yml @@ -8,12 +8,16 @@ services: volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped + environment: + - TERM=xterm solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 restart: unless-stopped environment: - ALFRESCO_HOST=alfresco-core + - GLOBAL_ALL_alfresco.cron=0/2 * * * * ? * + - GLOBAL_ALL_alfresco.lag=500 postgresql: image: docker.io/xenit/postgres diff --git a/apix-docker/70/docker-compose.yml b/apix-docker/70/docker-compose.yml index c90563cf..b889f486 100644 --- a/apix-docker/70/docker-compose.yml +++ b/apix-docker/70/docker-compose.yml @@ -8,6 +8,10 @@ services: volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped + environment: + - TERM=xterm + - GLOBAL_messaging.broker.url=failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true + - GLOBAL_localTransform.core-aio.url=http://transform-core-aio:8090/ solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 @@ -16,6 +20,8 @@ services: restart: unless-stopped environment: - ALFRESCO_HOST=alfresco-core + - GLOBAL_ALL_alfresco.cron=0/2 * * * * ? * + - GLOBAL_ALL_alfresco.lag=500 postgresql: image: docker.io/xenit/postgres diff --git a/apix-docker/71/docker-compose.yml b/apix-docker/71/docker-compose.yml index c90563cf..b889f486 100644 --- a/apix-docker/71/docker-compose.yml +++ b/apix-docker/71/docker-compose.yml @@ -8,6 +8,10 @@ services: volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped + environment: + - TERM=xterm + - GLOBAL_messaging.broker.url=failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true + - GLOBAL_localTransform.core-aio.url=http://transform-core-aio:8090/ solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 @@ -16,6 +20,8 @@ services: restart: unless-stopped environment: - ALFRESCO_HOST=alfresco-core + - GLOBAL_ALL_alfresco.cron=0/2 * * * * ? * + - GLOBAL_ALL_alfresco.lag=500 postgresql: image: docker.io/xenit/postgres diff --git a/apix-docker/72/docker-compose.yml b/apix-docker/72/docker-compose.yml index ea75e0aa..3d957119 100644 --- a/apix-docker/72/docker-compose.yml +++ b/apix-docker/72/docker-compose.yml @@ -8,6 +8,10 @@ services: volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped + environment: + - TERM=xterm + - GLOBAL_messaging.broker.url=failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true + - GLOBAL_localTransform.core-aio.url=http://transform-core-aio:8090/ solr: image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 @@ -16,6 +20,8 @@ services: restart: unless-stopped environment: - ALFRESCO_HOST=alfresco-core + - GLOBAL_ALL_alfresco.cron=0/2 * * * * ? * + - GLOBAL_ALL_alfresco.lag=500 postgresql: image: docker.io/xenit/postgres diff --git a/apix-docker/build.gradle b/apix-docker/build.gradle index bf1b8bca..f2b49257 100644 --- a/apix-docker/build.gradle +++ b/apix-docker/build.gradle @@ -31,25 +31,5 @@ subprojects { useComposeFiles.add(extraComposeFile) } } - - // Solr Tracking improvements -// environment.put 'GLOBAL_alfresco.cron', '0/2 * * * * ? *' -// environment.put 'GLOBAL_alfresco.lag', '500' -// environment.put 'GLOBAL_solr.http.socket.timeout','10000' - // Logging improvements - environment.put 'TERM', 'xterm' - if(subproject_alfresco_version.startsWith("7")) { - environment.put'GLOBAL_messaging.broker.url','failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true' - environment.put'GLOBAL_localTransform.core-aio.url','http://transform-core-aio:8090/' - // Needed for Solr indexing - environment.put 'GLOBAL_local.transform.service.enabled','true' - // Disable transformations and renditions - environment.put 'GLOBAL_contentPropertyRestrictions.enabled','false' - environment.put 'GLOBAL_ooo.enabled','false' - environment.put 'GLOBAL_jodconverter.enabled','false' - environment.put 'GLOBAL_transform.service.enabled','false' - environment.put 'GLOBAL_legacy.transform.service.enabled','false' - } } - } From 9ab11bf1698939deea30fc13777620e5a846dbcb Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Fri, 4 Nov 2022 11:15:05 +0200 Subject: [PATCH 22/90] ALFREDAPI-504 Correct max txn id lookup --- .../xenit/apix/util/AlfrescoServerInfo.java | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/AlfrescoServerInfo.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/AlfrescoServerInfo.java index 4db41541..74398eb0 100644 --- a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/AlfrescoServerInfo.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/util/AlfrescoServerInfo.java @@ -1,22 +1,27 @@ package eu.xenit.apix.util; import com.github.dynamicextensionsalfresco.osgi.OsgiService; -import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.service.descriptor.DescriptorService; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + @Service @OsgiService public class AlfrescoServerInfo { // Part of Alfresco Private API private final DescriptorService descriptorService; - private final NodeDAO nodeDAO; + private final DataSource dataSource; public AlfrescoServerInfo(@Qualifier("descriptorComponent") DescriptorService descriptorServiceParam, - NodeDAO nodeDAOParam) { + DataSource dataSourceParam) { descriptorService = descriptorServiceParam; - nodeDAO = nodeDAOParam; + dataSource = dataSourceParam; } public String getAlfrescoVersion() { @@ -25,7 +30,22 @@ public String getAlfrescoVersion() { .getVersion(); } + /** + * Tried using SearchTrackingComponent and NodeDAO to getMaxTxnId, but they are not as consistent and quick + * as getting it from alf_node table. + */ public long getAlfTransactionIdDAO() { - return nodeDAO.getMaxTxnId(); + try (Connection connection = dataSource.getConnection()) { + try(final Statement stmt = connection.createStatement()) { + try(final ResultSet rs = stmt.executeQuery("select max( transaction_id ) from alf_node")) { + if (rs.next()) { + return rs.getInt(1); + } + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + return -1; } } From 26cd4726339c84a8f2fa2380eb981b4b98a0f01e Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Fri, 4 Nov 2022 16:47:11 +0200 Subject: [PATCH 23/90] ALFREDAPI-504 Revert solr configuration --- apix-docker/62/docker-compose.yml | 2 -- apix-docker/70/docker-compose.yml | 2 -- apix-docker/71/docker-compose.yml | 2 -- apix-docker/72/docker-compose.yml | 2 -- 4 files changed, 8 deletions(-) diff --git a/apix-docker/62/docker-compose.yml b/apix-docker/62/docker-compose.yml index 8ad360d7..2e484c28 100644 --- a/apix-docker/62/docker-compose.yml +++ b/apix-docker/62/docker-compose.yml @@ -16,8 +16,6 @@ services: restart: unless-stopped environment: - ALFRESCO_HOST=alfresco-core - - GLOBAL_ALL_alfresco.cron=0/2 * * * * ? * - - GLOBAL_ALL_alfresco.lag=500 postgresql: image: docker.io/xenit/postgres diff --git a/apix-docker/70/docker-compose.yml b/apix-docker/70/docker-compose.yml index b889f486..9d9b6341 100644 --- a/apix-docker/70/docker-compose.yml +++ b/apix-docker/70/docker-compose.yml @@ -20,8 +20,6 @@ services: restart: unless-stopped environment: - ALFRESCO_HOST=alfresco-core - - GLOBAL_ALL_alfresco.cron=0/2 * * * * ? * - - GLOBAL_ALL_alfresco.lag=500 postgresql: image: docker.io/xenit/postgres diff --git a/apix-docker/71/docker-compose.yml b/apix-docker/71/docker-compose.yml index b889f486..9d9b6341 100644 --- a/apix-docker/71/docker-compose.yml +++ b/apix-docker/71/docker-compose.yml @@ -20,8 +20,6 @@ services: restart: unless-stopped environment: - ALFRESCO_HOST=alfresco-core - - GLOBAL_ALL_alfresco.cron=0/2 * * * * ? * - - GLOBAL_ALL_alfresco.lag=500 postgresql: image: docker.io/xenit/postgres diff --git a/apix-docker/72/docker-compose.yml b/apix-docker/72/docker-compose.yml index 3d957119..fa275fde 100644 --- a/apix-docker/72/docker-compose.yml +++ b/apix-docker/72/docker-compose.yml @@ -20,8 +20,6 @@ services: restart: unless-stopped environment: - ALFRESCO_HOST=alfresco-core - - GLOBAL_ALL_alfresco.cron=0/2 * * * * ? * - - GLOBAL_ALL_alfresco.lag=500 postgresql: image: docker.io/xenit/postgres From 77ebae8009b0c431daf9043630f01450816d0279 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski <6491638+todorinskiz@users.noreply.github.com> Date: Wed, 1 Feb 2023 10:27:54 +0200 Subject: [PATCH 24/90] ALFREDAPI-504 Removed local dependencies --- temp-dependencies/alfresco-mvc-aop-8.0.0.jar | Bin 18696 -> 0 bytes temp-dependencies/alfresco-mvc-rest-8.0.0.jar | Bin 33037 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 temp-dependencies/alfresco-mvc-aop-8.0.0.jar delete mode 100644 temp-dependencies/alfresco-mvc-rest-8.0.0.jar diff --git a/temp-dependencies/alfresco-mvc-aop-8.0.0.jar b/temp-dependencies/alfresco-mvc-aop-8.0.0.jar deleted file mode 100644 index 820ee76998e1b214461f27ed1e2e9179fc2bbddd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18696 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%0A+^k#^NSuZfN0|%XI5;*gj{tXX>}s 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 Lr2*gB?g0M}P?9DP diff --git a/temp-dependencies/alfresco-mvc-rest-8.0.0.jar b/temp-dependencies/alfresco-mvc-rest-8.0.0.jar deleted file mode 100644 index d79d4eacefc97f70605fe0de44ad7b7e69523980..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33037 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 Y Date: Wed, 1 Feb 2023 20:07:31 +0200 Subject: [PATCH 25/90] ALFREDAPI-504 Post-rebase fixes; Removed obsolete files --- alfresco/61/overrides.gradle | 5 ----- alfresco/72/overrides.gradle | 2 +- {apix-impl => alfresco}/73/overrides.gradle | 6 +++--- apix-impl/build.gradle | 2 +- .../{ => alfresco}/73/overrides.gradle | 0 .../xenit/apix/util/SolrTestHelperImpl.java | 0 apix-rest-v1/META-INF/readme.txt | 18 ---------------- apix-rest-v1/build.gradle | 21 ------------------- apix-rest-v1/build.properties | 9 -------- .../META-INF/spring/bundle-context-osgi.Noxml | 13 ------------ .../META-INF/spring/bundle-context.NOxml | 10 --------- .../out/production/resources/log4j.properties | 8 ------- apix-rest-v1/readme.txt | 18 ---------------- apix-rest-v1/template.mf | 4 ---- build.gradle | 6 +++--- settings.gradle | 2 +- 16 files changed, 9 insertions(+), 115 deletions(-) delete mode 100644 alfresco/61/overrides.gradle rename {apix-impl => alfresco}/73/overrides.gradle (52%) rename apix-integrationtests/{ => alfresco}/73/overrides.gradle (100%) rename apix-integrationtests/{ => alfresco}/73/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java (100%) delete mode 100644 apix-rest-v1/META-INF/readme.txt delete mode 100644 apix-rest-v1/build.properties delete mode 100644 apix-rest-v1/out/production/resources/META-INF/spring/bundle-context-osgi.Noxml delete mode 100644 apix-rest-v1/out/production/resources/META-INF/spring/bundle-context.NOxml delete mode 100644 apix-rest-v1/out/production/resources/log4j.properties delete mode 100644 apix-rest-v1/readme.txt delete mode 100644 apix-rest-v1/template.mf diff --git a/alfresco/61/overrides.gradle b/alfresco/61/overrides.gradle deleted file mode 100644 index a3f8f4f9..00000000 --- a/alfresco/61/overrides.gradle +++ /dev/null @@ -1,5 +0,0 @@ -ext { - alfresco_version = "6.1.2-ga" - alfresco_min_version = alfresco_version.substring(0, 3) + ".0" - alfresco_max_version = alfresco_version.substring(0, 3) + ".99" -} \ No newline at end of file diff --git a/alfresco/72/overrides.gradle b/alfresco/72/overrides.gradle index 81fc98a4..7624de02 100644 --- a/alfresco/72/overrides.gradle +++ b/alfresco/72/overrides.gradle @@ -1,5 +1,5 @@ ext { alfresco_version = "7.2.1" alfresco_min_version = alfresco_version.substring(0, 3) + ".0" - alfresco_max_version = null + alfresco_max_version = alfresco_version.substring(0, 3) + ".99" } diff --git a/apix-impl/73/overrides.gradle b/alfresco/73/overrides.gradle similarity index 52% rename from apix-impl/73/overrides.gradle rename to alfresco/73/overrides.gradle index c0d84b19..cd463bee 100644 --- a/apix-impl/73/overrides.gradle +++ b/alfresco/73/overrides.gradle @@ -1,9 +1,9 @@ description = "Xenit API-X implementation Alfresco 7.3" ext { - alfresco_version = alfresco_73_version + alfresco_version = '7.3.1' alfresco_repo_version = '17.175' - alfresco_dm_version = alfresco_73_dm_version - alfresco_min_version = "7.3" + alfresco_min_version = alfresco_version.substring(0, 3) + ".0" //Not setting alfresco_max_version here to make it easier to test on next Alfresco version (only for latest version) + alfresco_max_version = null // explicit null to overwrite properties from other projects (e.g. 7.2) } \ No newline at end of file diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index 0a2786f8..ac04b283 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -94,7 +94,7 @@ allprojects { alfrescoProvided('org.alfresco:alfresco-remote-api') implementation group: 'org.yaml', name: 'snakeyaml', version: '1.15' - implementation group: 'javax.validation', name: 'validation-api', version: '1.1.0.Final' + implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final' testImplementation platform("org.alfresco:acs-community-packaging:$alfresco_version") testImplementation 'org.alfresco:alfresco-repository' diff --git a/apix-integrationtests/73/overrides.gradle b/apix-integrationtests/alfresco/73/overrides.gradle similarity index 100% rename from apix-integrationtests/73/overrides.gradle rename to apix-integrationtests/alfresco/73/overrides.gradle diff --git a/apix-integrationtests/73/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java b/apix-integrationtests/alfresco/73/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java similarity index 100% rename from apix-integrationtests/73/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java rename to apix-integrationtests/alfresco/73/src/main/java/eu/xenit/apix/util/SolrTestHelperImpl.java diff --git a/apix-rest-v1/META-INF/readme.txt b/apix-rest-v1/META-INF/readme.txt deleted file mode 100644 index de894c13..00000000 --- a/apix-rest-v1/META-INF/readme.txt +++ /dev/null @@ -1,18 +0,0 @@ -To facilitate OSGi bundle manifest generation, the archetype offers the choice of two maven plugins. - -a. SpringSource Bundlor Plugin -Home page: http://www.springsource.org/bundlor - -"SpringSource� Bundlor is a tool that automates the detection of dependencies and the creation of OSGi -manifest directives for JARs after their creation." - -The Bundlor tool is enabled by default. - -b. Apache Felix Bundle Plugin -Home page: http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html - -"This plugin for Maven 2 is based on the BND tool from Peter Kriens. [...] The way you create a bundle -with BND is to tell it the content of the bundle's JAR file as a subset of the available classes." - - -To trigger the manifest generation (using either plugin), run: mvn package diff --git a/apix-rest-v1/build.gradle b/apix-rest-v1/build.gradle index e7b89619..d50a4a4a 100644 --- a/apix-rest-v1/build.gradle +++ b/apix-rest-v1/build.gradle @@ -19,19 +19,6 @@ apply from: "$rootProject.projectDir/alfresco/70/overrides.gradle" dependencies { implementation platform("org.alfresco:acs-community-packaging:$alfresco_version") -// implementation "org.springframework.boot:spring-boot-starter-parent:2.6.6" -// implementation "org.springframework.boot:spring-boot-starter-actuator:2.6.6" -//// implementation "org.springframework.boot:spring-boot-starter-integration:2.6.6" -// implementation("io.springfox:springfox-boot-starter:3.0.0") { -// exclude group: 'io.swagger', module: 'swagger-annotations' -// } -// implementation("io.springfox:springfox-swagger2:3.0.0") { -// exclude group: 'io.swagger', module: 'swagger-annotations' -// } -// implementation "io.springfox:springfox-swagger-ui:3.0.0" -// implementation "io.springfox:springfox-spring-web:3.0.0" -// implementation "io.springfox:springfox-spring-webmvc:3.0.0" -//// implementation "io.springfox:springfox-spring-integration-webmvc:3.0.0" // Alfresco dependency should be removed in the future alfrescoProvided("org.alfresco:alfresco-repository") @@ -42,14 +29,6 @@ dependencies { alfrescoProvided "com.gradecak.alfresco-mvc:alfresco-mvc-aop:$mvc" alfrescoProvided "javax.servlet:javax.servlet-api:4.0.1" -// compile(project(':de-swagger-reader')) - - // Overriding the dependencies in swagger to use the same version everywhere, ideally we - // can switch to a recent swagger version and have updated jackson versions. -// implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml" -// implementation "com.fasterxml.jackson.datatype:jackson-datatype-joda" - implementation group: 'io.swagger', name: 'swagger-annotations', version: swagger_version - testImplementation project(':apix-interface') testImplementation project(':apix-impl') testImplementation platform("org.alfresco:acs-community-packaging:$alfresco_version") diff --git a/apix-rest-v1/build.properties b/apix-rest-v1/build.properties deleted file mode 100644 index cfd2269e..00000000 --- a/apix-rest-v1/build.properties +++ /dev/null @@ -1,9 +0,0 @@ -source.. = src/main/java/,src/main/resources/,src/test/java,src/test/resources -output.. = target/classes/,target/test-classes -bin.includes = META-INF/,\ - .,\ - target/classes/ -src.includes = src/main/java/,\ - src/main/resources/,\ - src/test/java/,\ - src/test/resources/ diff --git a/apix-rest-v1/out/production/resources/META-INF/spring/bundle-context-osgi.Noxml b/apix-rest-v1/out/production/resources/META-INF/spring/bundle-context-osgi.Noxml deleted file mode 100644 index 3b18d880..00000000 --- a/apix-rest-v1/out/production/resources/META-INF/spring/bundle-context-osgi.Noxml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apix-rest-v1/out/production/resources/META-INF/spring/bundle-context.NOxml b/apix-rest-v1/out/production/resources/META-INF/spring/bundle-context.NOxml deleted file mode 100644 index 309ae12d..00000000 --- a/apix-rest-v1/out/production/resources/META-INF/spring/bundle-context.NOxml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apix-rest-v1/out/production/resources/log4j.properties b/apix-rest-v1/out/production/resources/log4j.properties deleted file mode 100644 index 18cfaa3f..00000000 --- a/apix-rest-v1/out/production/resources/log4j.properties +++ /dev/null @@ -1,8 +0,0 @@ -log4j.rootCategory=INFO, stdout -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout.ConversionPattern=%t %p [%c] - %m%n -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.threshold=TRACE - -#log4j.logger.org.springframework.osgi=DEBUG -#log4j.logger.org.springframework=DEBUG \ No newline at end of file diff --git a/apix-rest-v1/readme.txt b/apix-rest-v1/readme.txt deleted file mode 100644 index de894c13..00000000 --- a/apix-rest-v1/readme.txt +++ /dev/null @@ -1,18 +0,0 @@ -To facilitate OSGi bundle manifest generation, the archetype offers the choice of two maven plugins. - -a. SpringSource Bundlor Plugin -Home page: http://www.springsource.org/bundlor - -"SpringSource� Bundlor is a tool that automates the detection of dependencies and the creation of OSGi -manifest directives for JARs after their creation." - -The Bundlor tool is enabled by default. - -b. Apache Felix Bundle Plugin -Home page: http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html - -"This plugin for Maven 2 is based on the BND tool from Peter Kriens. [...] The way you create a bundle -with BND is to tell it the content of the bundle's JAR file as a subset of the available classes." - - -To trigger the manifest generation (using either plugin), run: mvn package diff --git a/apix-rest-v1/template.mf b/apix-rest-v1/template.mf deleted file mode 100644 index 94121f6f..00000000 --- a/apix-rest-v1/template.mf +++ /dev/null @@ -1,4 +0,0 @@ -Excluded-Exports: - *.internal* -Unversioned-Imports: - * diff --git a/build.gradle b/build.gradle index ee034990..9ad6bb9d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ plugins { // Centralize plugin version management id 'be.vbgn.ci-detect' version '0.5.0' apply false - id 'eu.xenit.de' version '2.1.3' apply false + id 'eu.xenit.de' version '3.0.0' apply false id 'eu.xenit.amp' version '1.1.0' apply false id 'eu.xenit.alfresco' version '1.1.0' apply false id 'eu.xenit.docker-alfresco' version '5.3.1' apply false id 'eu.xenit.docker-compose' version '5.3.1' apply false - id 'eu.xenit.alfresco-remote-testrunner' version '2.0.0' apply false + id 'eu.xenit.alfresco-remote-testrunner' version '2.0.1' apply false } def static getVersionQualifier(String branch_name) { @@ -19,7 +19,7 @@ def static getVersionQualifier(String branch_name) { ext { versionWithoutQualifier = '4.0.0' - de_version = "2.1.3" + de_version = "3.0.0" mvc = "8.0.0" jackson_version = '2.8.3' swagger_version = "1.5.7" // 2.2.4 diff --git a/settings.gradle b/settings.gradle index 26d46d3b..02e8d69a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,7 +8,7 @@ include ':apix-integrationtests' include ':apix-integrationtests:model-amp' ext { - versions = ["6.1", "6.2", "7.0", "7.1", "7.2", "7.3"] + versions = ["6.2", "7.0", "7.1", "7.2", "7.3"] } for(String version : versions) { From b63d9262f785ea078acc752e55949e3ff6425b7f Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski <6491638+todorinskiz@users.noreply.github.com> Date: Wed, 1 Feb 2023 20:34:12 +0200 Subject: [PATCH 26/90] ALFREDAPI-504 Completely dropped Swagger, incl annotations --- apix-interface/build.gradle | 2 - .../java/eu/xenit/apix/node/INodeService.java | 3 - .../eu/xenit/apix/search/SearchQuery.java | 8 - .../translation/PropertyTranslationValue.java | 4 - .../rest/AlfredApiRestServletContext.java | 101 +------ .../staging/workflow/WorkflowWebscript.java | 109 +------- .../apix/rest/v0/search/SearchQueryV0.java | 3 - .../apix/rest/v1/ApixSwaggerDescription.java | 31 --- .../apix/rest/v1/DocumentationWebscript.java | 201 -------------- .../xenit/apix/rest/v1/GeneralWebscript.java | 5 - .../xenit/apix/rest/v1/bulk/BulkRequest.java | 4 - .../apix/rest/v1/bulk/BulkSubResult.java | 3 - .../apix/rest/v1/bulk/BulkWebscript1.java | 5 - .../v1/categories/CategoryWebScript1.java | 5 - .../ConfigurationWebscript1.java | 38 +-- .../v1/dictionary/DictionaryWebScript1.java | 20 -- .../rest/v1/nodes/ChangeParentOptions.java | 2 - .../v1/nodes/CreateAssociationOptions.java | 3 - .../apix/rest/v1/nodes/CreateNodeOptions.java | 2 - .../apix/rest/v1/nodes/InheritFromParent.java | 2 - .../apix/rest/v1/nodes/NodesWebscript1.java | 249 ------------------ .../apix/rest/v1/people/PeopleWebscript1.java | 7 - .../v1/properties/PropertiesWebScript1.java | 5 - .../apix/rest/v1/search/SearchWebScript1.java | 118 --------- .../apix/rest/v1/sites/SitesWebscript1.java | 17 -- .../apix/rest/v1/temp/LogsWebscript.java | 2 - .../xenit/apix/rest/v1/temp/WIPWebscript.java | 8 - .../translation/TranslationsWebscript1.java | 7 - .../VersionHistoryWebScript1.java | 22 -- .../rest/v1/workingcopies/CheckoutBody.java | 4 - .../WorkingcopiesWebscript1.java | 21 -- .../apix/rest/v2/groups/GroupsWebscript.java | 13 - .../rest/v2/groups/SetSubgroupOptions.java | 2 - .../v2/groups/SetUsersInGroupOptions.java | 2 - .../apix/rest/v2/nodes/NodesWebscriptV2.java | 52 ---- .../apix/rest/v2/people/PeopleWebscript.java | 13 - .../apix/rest/DocumentationWebscriptTest.java | 67 ----- build.gradle | 1 - 38 files changed, 14 insertions(+), 1147 deletions(-) delete mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixSwaggerDescription.java delete mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/DocumentationWebscript.java delete mode 100644 apix-rest-v1/src/test/java/eu/xenit/apix/rest/DocumentationWebscriptTest.java diff --git a/apix-interface/build.gradle b/apix-interface/build.gradle index 718bbfa8..e406cda6 100644 --- a/apix-interface/build.gradle +++ b/apix-interface/build.gradle @@ -28,8 +28,6 @@ dependencies { implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jackson_version implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: jackson_version implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jackson_version - implementation group: 'io.swagger', name: 'swagger-annotations', version: swagger_version -// implementation "io.swagger.core.v3:swagger-annotations:$swagger_version" testImplementation group: 'junit', name: 'junit', version: '4.12' } diff --git a/apix-interface/src/main/java/eu/xenit/apix/node/INodeService.java b/apix-interface/src/main/java/eu/xenit/apix/node/INodeService.java index 44af1e61..538cc8c6 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/node/INodeService.java +++ b/apix-interface/src/main/java/eu/xenit/apix/node/INodeService.java @@ -6,7 +6,6 @@ import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.data.QName; import eu.xenit.apix.data.StoreRef; -import io.swagger.annotations.Api; import java.io.InputStream; import java.util.List; import java.util.Map; @@ -14,8 +13,6 @@ /** * Service for operations on nodes. */ -// FIXME What is this annotation doing here? -@Api(value = "/metadata", produces = "application/json") public interface INodeService { /** diff --git a/apix-interface/src/main/java/eu/xenit/apix/search/SearchQuery.java b/apix-interface/src/main/java/eu/xenit/apix/search/SearchQuery.java index 59df93ca..392c6a1b 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/search/SearchQuery.java +++ b/apix-interface/src/main/java/eu/xenit/apix/search/SearchQuery.java @@ -5,8 +5,6 @@ import eu.xenit.apix.data.QName; import eu.xenit.apix.data.StoreRef; import eu.xenit.apix.search.nodes.SearchSyntaxNode; -import io.swagger.annotations.ApiModelProperty; -//import io.swagger.v3.oas.annotations.media.Schema; import java.util.ArrayList; import java.util.Arrays; @@ -25,8 +23,6 @@ */ public class SearchQuery { -// @Schema(required = true) - @ApiModelProperty(required = true) private SearchSyntaxNode query; private PagingOptions paging = new PagingOptions(); private FacetOptions facets = new FacetOptions(); @@ -130,12 +126,8 @@ public static class FacetOptions { private boolean enabled; -// @Schema(description = "Limits the number of values returned per facet") - @ApiModelProperty("Limits the number of values returned per facet") private Integer limit = -1; -// @Schema(description = "Return only facet values with count >= mincount") - @ApiModelProperty("Return only facet values with count >= mincount") private Integer mincount; public List custom; diff --git a/apix-interface/src/main/java/eu/xenit/apix/translation/PropertyTranslationValue.java b/apix-interface/src/main/java/eu/xenit/apix/translation/PropertyTranslationValue.java index 433a8b1f..62ff3f0a 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/translation/PropertyTranslationValue.java +++ b/apix-interface/src/main/java/eu/xenit/apix/translation/PropertyTranslationValue.java @@ -1,8 +1,6 @@ package eu.xenit.apix.translation; import eu.xenit.apix.data.QName; -import io.swagger.annotations.ApiModelProperty; -//import io.swagger.v3.oas.annotations.media.Schema; import java.util.Map; @@ -12,8 +10,6 @@ */ public class PropertyTranslationValue extends TranslationValue { -// @Schema(type = "Map[string,string]") - @ApiModelProperty(dataType = "Map[string,string]") private Map values; public PropertyTranslationValue() { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java index 14720054..37d9d2e7 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java @@ -12,48 +12,21 @@ import eu.xenit.apix.search.json.SearchNodeJsonParser; import org.alfresco.rest.framework.jacksonextensions.RestJsonModule; import org.alfresco.service.namespace.NamespaceService; -import org.springframework.beans.factory.InitializingBean; -//import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -//import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; -//import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -//import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration; -import org.springframework.context.annotation.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.PropertySource; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -//import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -//import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; -import org.springframework.web.servlet.mvc.method.RequestMappingInfo; -import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping; -//import springfox.documentation.RequestHandler; -//import springfox.documentation.builders.PathSelectors; -//import springfox.documentation.builders.RequestHandlerSelectors; -//import springfox.documentation.spi.DocumentationType; -//import springfox.documentation.spi.service.RequestHandlerProvider; -//import springfox.documentation.spring.web.WebMvcRequestHandler; -//import springfox.documentation.spring.web.paths.Paths; -//import springfox.documentation.spring.web.plugins.Docket; -//import springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper; -//import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider; -//import springfox.documentation.spring.web.readers.operation.HandlerMethodResolver; -//import springfox.documentation.swagger2.annotations.EnableSwagger2; -import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import java.util.Arrays; import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; @Configuration @EnableWebMvc -//@EnableSwagger2 -//@EnableAutoConfiguration(exclude = { -// DataSourceAutoConfiguration.class, -// ActiveMQAutoConfiguration.class, -// FreeMarkerAutoConfiguration.class -//}) @PropertySource(value = { "classpath:application.properties" }) // should pick up other controllers from the same package by default @ComponentScan(basePackages = { "eu.xenit.apix" }) @@ -108,68 +81,4 @@ public boolean isMultipart(HttpServletRequest request) { resolver.setDefaultEncoding("utf-8"); return resolver; } - -// @Bean -// public Docket api() { -// return new Docket(DocumentationType.SWAGGER_2) -// .select() -// .paths(PathSelectors.ant("/api/**")) -// .apis(RequestHandlerSelectors.basePackage("eu.xenit.apix")) -// .build(); -// } - -// @Override -// public void addResourceHandlers(ResourceHandlerRegistry registry) { -// registry.addResourceHandler("/api/swagger-ui.html**") -// .addResourceLocations("classpath:/META-INF/resources/swagger-ui.html"); -// registry.addResourceHandler("/api/webjars/**") -// .addResourceLocations("classpath:/META-INF/resources/webjars/"); -// } -// -// @Override -// public void addViewControllers(ViewControllerRegistry registry) { -// registry.addRedirectViewController( -// "/apix/v2/api-docs", -// "/v2/api-docs" -// ); -// registry.addRedirectViewController( -// "/apix/swagger-resources/configuration/ui", -// "/swagger-resources/configuration/ui" -// ); -// registry.addRedirectViewController( -// "/apix/swagger-resources/configuration/security", -// "/swagger-resources/configuration/security" -// ); -// registry.addRedirectViewController( -// "/apix/swagger-resources", -// "/swagger-resources" -// ); -// } - -// @Bean -// public InitializingBean removeSpringfoxHandlerProvider(DocumentationPluginsBootstrapper bootstrapper) { -// return () -> bootstrapper.getHandlerProviders().removeIf(WebMvcRequestHandlerProvider.class::isInstance); -// } -// -// @Bean -// public RequestHandlerProvider customRequestHandlerProvider(Optional servletContext, -// HandlerMethodResolver methodResolver, -// List handlerMappings) { -// String contextPath = servletContext.map(ServletContext::getContextPath).orElse(Paths.ROOT); -// return () -> handlerMappings.stream() -// .filter(mapping -> !mapping.getClass().getSimpleName() -// .equals("IntegrationRequestMappingHandlerMapping")) -// .map(mapping -> mapping.getHandlerMethods().entrySet()) -// .flatMap(Set::stream) -// .map(entry -> new WebMvcRequestHandler(contextPath, methodResolver, -// tweakInfo(entry.getKey()), entry.getValue())) -// .sorted(RequestHandler.byPatternsCondition()) -// .collect(Collectors.toList()); -// } -// -// RequestMappingInfo tweakInfo(RequestMappingInfo info) { -// if (info.getPathPatternsCondition() == null) return info; -// String[] patterns = info.getPathPatternsCondition().getPatternValues().toArray(String[]::new); -// return info.mutate().options(new RequestMappingInfo.BuilderConfiguration()).paths(patterns).build(); -// } } \ No newline at end of file diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java index b78868b1..90610dbe 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java @@ -1,6 +1,5 @@ package eu.xenit.apix.rest.staging.workflow; -import eu.xenit.apix.search.SearchQueryResult; import eu.xenit.apix.workflow.IWorkflowService; import eu.xenit.apix.workflow.model.Task; import eu.xenit.apix.workflow.model.Workflow; @@ -10,12 +9,6 @@ import eu.xenit.apix.workflow.search.TaskOrWorkflowSearchResult; import eu.xenit.apix.workflow.search.TaskSearchQuery; import eu.xenit.apix.workflow.search.WorkflowSearchQuery; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import java.io.Serializable; import java.util.Arrays; import java.util.HashSet; @@ -40,46 +33,6 @@ public class WorkflowWebscript { private static final Logger logger = LoggerFactory.getLogger(WorkflowWebscript.class); - /// - private static final String WorkflowSearchQueryDocumentationSample = "{\n" + - "\t\"filters\": [],\n" + - "\t\"facets\": [\n" + - "\t\t\"{http://www.alfresco.org/model/content/1.0}owner\",\n" + - "\t\t\"{http://www.alfresco.org/model/bpm/1.0}dueDate\",\n" + - "\t\t\"{http://www.alfresco.org/model/bpm/1.0}startDate\",\n" + - "\t\t\"{http://www.alfresco.org/model/bpm/1.0}endDate\",\n" + - "\t\t\"{http://www.alfresco.org/model/bpm/1.0}workflowPriority\"\n" + - "\t],\n" + - "\t\"scope\": \"WorkflowsIveStarted\",\n" + - "\t\"paging\": {\n" + - "\t\t\"skip\": 0,\n" + - "\t\t\"limit\": 15\n" + - "\t}\n" + - "}"; - private static final String TaskSearchQueryDocumentationSample = "{\n" + - "\t\"facets\": [\n" + - "\t\t\"{http://www.alfresco.org/model/content/1.0}owner\",\n" + - "\t\t\"{http://www.alfresco.org/model/bpm/1.0}priority\"\n" + - "\t],\n" + - "\t\"filters\": [],\n" + - "\t\"scope\": \"MyTasks\"|\"MyPooledTasks\"|\"AllTasks\",\n" + - "\t\"paging\": {\n" + - "\t\t\"skip\": 0,\n" + - "\t\t\"limit\": 15\n" + - "\t}\n" + - "}"; - private static final String WorkflowChangesOrTaskChangesDocumentationSample = "{\n" + - "\t\"propertiesToSet\": {\n" + - "\t\t\"{http://www.alfresco.org/model/bpm/1.0}priority\": \"1\",\n" + - "\t\t\"{http://www.alfresco.org/model/bpm/1.0}status\": \"On Hold\",\n" + - "\t\t\"{http://www.alfresco.org/model/bpm/1.0}startDate\": \"2018-01-29T23:00:00.000Z\",\n" + - "\t\t\"{http://www.alfresco.org/model/bpm/1.0}title\": \"Task 1\",\n" + - "\t\t\"{http://www.alfresco.org/model/bpm/1.0}dueDate\": \"2018-01-24T23:00:00.000Z\",\n" + - "\t\t\"{http://www.alfresco.org/model/bpm/1.0}description\": \"Task allocated by colleague 2\"\n" + - "\t}\n" + - "}"; - /// - private final IWorkflowService workflowService; public WorkflowWebscript(@Qualifier("eu.xenit.apix.workflow.IWorkflowService") IWorkflowService workflowService) { @@ -90,10 +43,8 @@ public WorkflowWebscript(@Qualifier("eu.xenit.apix.workflow.IWorkflowService") I value = "/staging/workflows/definitions", produces = MediaType.APPLICATION_JSON_VALUE ) - @ApiOperation(value = "Retrieve the definitions for all defined workflows") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = WorkflowDefinitionList.class)) - public ResponseEntity getWorkflowDefinitions(@RequestParam(required = false) - @ApiParam(value = "Comma separated definition names to exclude.") String[] exclude) { + public ResponseEntity getWorkflowDefinitions( + @RequestParam(required = false) String[] exclude) { List definitions = workflowService.getAllDefinitions(); if (exclude != null && exclude.length > 0) { @@ -105,21 +56,11 @@ public ResponseEntity getWorkflowDefinitions(@RequestPar } @GetMapping(value = "/workflows/definition/{name}") - @ApiOperation(value = "Retrieve the definition for the specified workflow name") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = WorkflowDefinition.class)) public ResponseEntity getWorkflowDefinition(@PathVariable final String name) { return responseFrom(workflowService.getWorkflowDefinition(name)); } @PostMapping(value = "/workflows/search") - @ApiOperation(value = "Returns a collection of workflow instances", - notes = "The result collection of workflow instances is sorted and filtered as requested in the provided" + - " WorkflowSearchQuery\nWorkflowSearchQuery Sample:\n" + WorkflowSearchQueryDocumentationSample) - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = SearchQueryResult.class)) - @ApiImplicitParams({@ApiImplicitParam( - dataType = "eu.xenit.apix.workflow.WorkflowSearchQuery", - paramType = "body", - name = "body")}) public ResponseEntity workflowsActiviti(@RequestBody final WorkflowSearchQuery query) { TaskOrWorkflowSearchResult result = workflowService.searchWorkflows(query); logger.debug("Found results for workflows, # of results: {}", result.results.size()); @@ -128,21 +69,11 @@ public ResponseEntity workflowsActiviti(@RequestBody } @PostMapping(value = "/tasks/search") - @ApiOperation(value = "Returns a collection of workflow tasks", - notes = "The result collection of workflow tasks is sorted and filtered as requested in the provided" + - " TaskSearchQuery\nTaskSearchQuery Sample:\n" + TaskSearchQueryDocumentationSample) - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = SearchQueryResult.class)) - @ApiImplicitParams({@ApiImplicitParam( - dataType = "eu.xenit.apix.workflow.TaskSearchQuery", - paramType = "body", - name = "body")}) public ResponseEntity tasksActiviti(@RequestBody final TaskSearchQuery query) { return responseFrom(workflowService.searchTasks(query)); } @GetMapping(value = "/workflows/{id}") - @ApiOperation(value = "Retrieves a workflow with the provided id") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Task.class)) public ResponseEntity workflow(@PathVariable final String id) { return responseFrom(workflowService.getWorkflowInfo(id)); } @@ -155,43 +86,24 @@ public ResponseEntity startWorkflow(@PathVariable final String id, } @GetMapping(value = "/tasks/{id}") - @ApiOperation(value = "Retrieves a workflow task with the provided id") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Task.class)) public ResponseEntity task(@PathVariable final String id) { responseFrom(workflowService.getTaskInfo(id)); return ResponseEntity.ok().build(); } @PutMapping(value = "/workflows/{id}") - @ApiOperation(value = "[Deprecated] Updates a workflow with the provided id, with the provided information from" + - " the provided WorkflowChanges\nWorkflowChanges Sample:\n" - + WorkflowChangesOrTaskChangesDocumentationSample) - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Workflow.class)) - @ApiImplicitParams({@ApiImplicitParam( - dataType = "eu.xenit.apix.workflow.model.WorkflowChanges", - paramType = "body", - name = "body")}) public ResponseEntity updateWorkflow(@PathVariable final String id, @RequestBody final WorkflowOrTaskChanges changes) { return responseFrom(workflowService.updateWorkflow(id, changes)); } @DeleteMapping(value = "/workflows/{id}") - @ApiOperation(value = "Cancels a workflow with the provided id") - @ApiResponses(@ApiResponse(code = 200, message = "Success")) public ResponseEntity cancelWorkflow(@PathVariable final String id) { workflowService.cancelWorkflow(id); return ResponseEntity.ok().build(); } @PutMapping(value = "/tasks/{id}") - @ApiOperation(value = "Updates a workflow task with the provided id, with the provided information from" + - " the provided TaskChanges\nTaskChanges Sample:\n" + WorkflowChangesOrTaskChangesDocumentationSample) - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Task.class)) - @ApiImplicitParams({@ApiImplicitParam( - dataType = "eu.xenit.apix.workflow.model.TaskChanges", - paramType = "body", - name = "body")}) public ResponseEntity updateTask(@PathVariable final String id, @RequestBody final WorkflowOrTaskChanges changes) { try { @@ -204,13 +116,6 @@ public ResponseEntity updateTask(@PathVariable final String id, } @PostMapping(value = "/staging/tasks/claim") - @ApiOperation(value = "Claims the task with the provided id for a user", - notes = "The user parameter is optional. If not provided, Alfred API will default to the current user") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = SearchQueryResult.class)) - @ApiImplicitParams({@ApiImplicitParam( - dataType = "String", - paramType = "body", - name = "body")}) public ResponseEntity claimTask(@RequestBody final Map body) { logger.debug("Input: {}", body); String id = body.get("id"); @@ -228,12 +133,6 @@ public ResponseEntity claimTask(@RequestBody final Map bod } @PostMapping(value = "/staging/tasks/release") - @ApiOperation(value = "Releases the task with the provided id") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = SearchQueryResult.class)) - @ApiImplicitParams({@ApiImplicitParam( - dataType = "String", - paramType = "body", - name = "body")}) public ResponseEntity releaseTask(@RequestBody final Map body) { logger.debug("Setting owner of task {}", body); String id = body.get("id"); @@ -242,15 +141,11 @@ public ResponseEntity releaseTask(@RequestBody final Map b } @PostMapping(value = "/staging/tasks/{id}/end/{transition}") - @ApiOperation(value = "Ends the workflow task with the provided id with the provided transition as next") - @ApiResponses(@ApiResponse(code = 200, message = "Success")) public void transitionTask(@PathVariable String id, @PathVariable String transition) { workflowService.endTask(id, transition); } @GetMapping(value = "/staging/workflows/generate/{amount}/{username}") - @ApiOperation(value = "[DEV] Generate an amount of workflows for username") - @ApiResponses(@ApiResponse(code = 200, message = "Success")) public void generateWorkflow(@PathVariable final int amount, @PathVariable final String username) { workflowService.GenerateWorkflows(amount, username); } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchQueryV0.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchQueryV0.java index 462f4c0d..b1d797e6 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchQueryV0.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchQueryV0.java @@ -5,7 +5,6 @@ import eu.xenit.apix.data.QName; import eu.xenit.apix.search.SearchQuery; import eu.xenit.apix.search.nodes.SearchSyntaxNode; -import io.swagger.annotations.ApiModelProperty; import java.util.ArrayList; import java.util.List; @@ -85,9 +84,7 @@ public static class FacetOptions { //private ArrayList fields; private boolean retrieveDefaults = false; - @ApiModelProperty("Limits the number of values returned per facet") private Integer limit = -1; - @ApiModelProperty("Return only facet values with count >= mincount") private Integer mincount; public boolean isRetrieveDefaults() { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixSwaggerDescription.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixSwaggerDescription.java deleted file mode 100644 index fdbf3ac0..00000000 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixSwaggerDescription.java +++ /dev/null @@ -1,31 +0,0 @@ -package eu.xenit.apix.rest.v1; - -import io.swagger.annotations.Contact; -import io.swagger.annotations.Info; -import io.swagger.annotations.License; -import io.swagger.annotations.SwaggerDefinition; -import io.swagger.annotations.Tag; - -/** - * Created by Michiel Huygen on 14/03/2016. - */ -@SwaggerDefinition( - info = @Info( - description = "This is the swagger specification for Api-X REST API" + - "\n\n" + - "Examples can be found at: https://docs.xenit.eu/alfred-api", - version = "2.0.0", - title = "Api-X REST API", - //termsOfService = "http://swagger.io/terms/", - contact = @Contact(name = "XeniT", email = "engineering@xenit.eu", url = "http://www.xenit.eu"), - license = @License(name = "GNU Lesser General Public License v3", url = "https://www.gnu.org/licenses/lgpl-3.0.txt") - ), - //consumes = {"application/json", "application/xml"}, - produces = {"application/json"}, - schemes = {SwaggerDefinition.Scheme.HTTP, SwaggerDefinition.Scheme.HTTPS}, - tags = {@Tag(name = "WIP", description = "Dont use in production!")} - //tags = {@Tag(name = "metadata", description = "Operations on node metadata")} -) -public class ApixSwaggerDescription { - -} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/DocumentationWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/DocumentationWebscript.java deleted file mode 100644 index 55918f74..00000000 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/DocumentationWebscript.java +++ /dev/null @@ -1,201 +0,0 @@ -//package eu.xenit.apix.rest.v1; -// -//import com.fasterxml.jackson.databind.type.SimpleType; -//import eu.xenit.apix.data.NodeRef; -//import eu.xenit.apix.data.QName; -//import eu.xenit.apix.rest.v1.bulk.BulkWebscript1; -//import eu.xenit.apix.rest.v1.categories.CategoryWebScript1; -//import eu.xenit.apix.rest.v1.configuration.ConfigurationWebscript1; -//import eu.xenit.apix.rest.v1.dictionary.DictionaryWebScript1; -//import eu.xenit.apix.rest.v1.nodes.NodesWebscript1; -//import eu.xenit.apix.rest.v1.people.PeopleWebscript1; -//import eu.xenit.apix.rest.v1.properties.PropertiesWebScript1; -//import eu.xenit.apix.rest.v1.search.SearchWebScript1; -//import eu.xenit.apix.rest.v1.sites.SitesWebscript1; -//import eu.xenit.apix.rest.v1.temp.WIPWebscript; -//import eu.xenit.apix.rest.v1.translation.TranslationsWebscript1; -//import eu.xenit.apix.rest.v1.versionhistory.VersionHistoryWebScript1; -//import eu.xenit.apix.rest.v1.workingcopies.WorkingcopiesWebscript1; -//import eu.xenit.apix.rest.v2.RestV2Config; -//import eu.xenit.apix.rest.v2.nodes.NodesWebscriptV2; -//import eu.xenit.apix.version.IVersionService; -//import eu.xenit.apix.web.IWebUtils; -//import eu.xenit.swagger.reader.Reader; -//import io.swagger.annotations.ApiOperation; -//import io.swagger.annotations.ApiResponse; -//import io.swagger.annotations.ApiResponses; -//import io.swagger.converter.ModelConverter; -//import io.swagger.converter.ModelConverterContext; -//import io.swagger.converter.ModelConverters; -//import io.swagger.models.Model; -//import io.swagger.models.ModelImpl; -//import io.swagger.models.Operation; -//import io.swagger.models.Path; -//import io.swagger.models.Response; -//import io.swagger.models.Scheme; -//import io.swagger.models.Swagger; -//import io.swagger.models.properties.FileProperty; -//import io.swagger.models.properties.Property; -//import io.swagger.util.Json; -//import java.io.IOException; -//import java.lang.annotation.Annotation; -//import java.lang.reflect.Type; -//import java.util.ArrayList; -//import java.util.HashMap; -//import java.util.Iterator; -//import java.util.List; -//import java.util.Map; -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -//import org.springframework.beans.factory.annotation.Autowired; -//import org.springframework.extensions.surf.util.URLEncoder; -//import org.springframework.extensions.webscripts.WebScriptRequest; -//import org.springframework.extensions.webscripts.WebScriptResponse; -//import org.springframework.stereotype.Component; -// -//@WebScript( -// baseUri = RestV1Config.BaseUrl + "/docs", -// families = {RestV1Config.Family}, -// defaultFormat = "json", -// description = "Access API Documentation", -// value = "Documentation") -//@Component("eu.xenit.apix.rest.v1.DocumentationWebscript") -//@Authentication(AuthenticationType.USER) -//public class DocumentationWebscript extends ApixV1Webscript {//implements BeanFactoryAware{ -// -// Logger logger = LoggerFactory.getLogger(DocumentationWebscript.class); -// -// private IVersionService versionService; -// private IWebUtils webUtils; -// -// @Autowired -// public DocumentationWebscript(IVersionService versionService, IWebUtils webUtils) { -// this.versionService = versionService; -// this.webUtils = webUtils; -// } -// -// @Uri(value = "/swagger.json", method = HttpMethod.GET) -// @ApiOperation("The Swagger Spec for Alfred API") -// @ApiResponses(@ApiResponse(code = 200, message = "Success")) -// public void execute(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) throws IOException { -// webScriptResponse.setContentType("json"); -// Swagger s = generateSwagger(); -// Json.mapper().writeValue(webScriptResponse.getOutputStream(), s); -// } -// -// @Uri(value = "/ui", method = HttpMethod.GET) -// public void redirectToSwaggerUi(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) { -// webScriptResponse.setStatus(302); -// String swaggerUi = webScriptRequest.getServiceContextPath() + "/swagger/ui/"; -// String servicePath = webScriptRequest.getServicePath(); -// String swaggerJsonUrl = servicePath.substring(0, servicePath.lastIndexOf(47) + 1) + "swagger.json"; -// webScriptResponse.setHeader("Location", swaggerUi + "?url=" + URLEncoder.encode(swaggerJsonUrl)); -// } -// -// public Swagger generateSwagger() { -// Reader r = new Reader(); -// // Correctly sets QName, Noderef, etc because swagger reader doesnt understand -// ModelConverters.getInstance().addConverter(new ModelConverter() { -// @Override -// public Property resolveProperty(Type type, ModelConverterContext context, Annotation[] annotations, -// Iterator chain) { -// if (chain.hasNext()) { -// return chain.next().resolveProperty(type, context, annotations, chain); -// } -// return null; -// } -// -// @Override -// public Model resolve(Type type, ModelConverterContext context, Iterator chain) { -// if (type instanceof SimpleType) { -// Class cls = ((SimpleType) type).getRawClass();// No clue why this happens -// -// if (cls.equals(NodeRef.class)) { -// ModelImpl noderefModel = new ModelImpl(); -// noderefModel.setName("NodeRef"); -// noderefModel.setType("string"); -// noderefModel.setExample("workspace://SpacesStore/987-978-79-797-797-978"); -// return noderefModel; -// } -// if (cls.equals(QName.class)) { -// ModelImpl noderefModel = new ModelImpl(); -// noderefModel.setName("QName"); -// noderefModel.setType("string"); -// noderefModel.setExample("{http://www.alfresco.org/model/content/1.0}content"); -// return noderefModel; -// } -// } -// -// if (chain.hasNext()) { -// return chain.next().resolve(type, context, chain); -// } -// return null; -// } -// }); -// // Ignore special DE webscript -// r.setIgnoredRoutes(new String[]{"/apix/v1/docs/ui"}); -// -// r.read(ApixSwaggerDescription.class); -// r.read(BulkWebscript1.class); -// r.read(CategoryWebScript1.class); -// r.read(ConfigurationWebscript1.class); -// r.read(DictionaryWebScript1.class); -// r.read(DocumentationWebscript.class); -// r.read(GeneralWebscript.class); -// r.read(NodesWebscript1.class); -// r.read(SearchWebScript1.class); -// r.read(SitesWebscript1.class); -// r.read(TranslationsWebscript1.class); -// r.read(VersionHistoryWebScript1.class); -// r.read(WIPWebscript.class); -// r.read(WorkingcopiesWebscript1.class); -// r.read(PeopleWebscript1.class); -// r.read(PropertiesWebScript1.class); -// r.read(eu.xenit.apix.rest.v2.people.PeopleWebscript.class); -// r.read(eu.xenit.apix.rest.v2.groups.GroupsWebscript.class); -// r.read(NodesWebscriptV2.class); -// -// addSwaggerUIOperation(r); -// -// r.getSwagger().getInfo().setVersion(versionService.getVersionDescription().getVersion()); -// -// r.getSwagger().setSchemes(getSchemes()); -// r.getSwagger().setBasePath("/alfresco/s" + RestV1Config.ApixUrl); -// Map paths = r.getSwagger().getPaths(); -// HashMap newPaths = new HashMap<>(); -// for (Map.Entry entry : paths.entrySet()) { -// if (!entry.getKey().startsWith(RestV1Config.BaseUrl) && !entry.getKey().startsWith(RestV2Config.BaseUrl)) { -// throw new RuntimeException( -// "Extract an operation from a webscript which does not start with the BaseUrl: " -// + entry.getKey()); -// } -// newPaths.put(entry.getKey().substring(RestV1Config.ApixUrl.length()), entry.getValue()); -// } -// r.getSwagger().setPaths(newPaths); -// return r.getSwagger(); -// } -// -// private void addSwaggerUIOperation(Reader r) { -// Operation op = new Operation(); -// Response response = new Response().description("Swagger UI interface"); -// response.schema(new FileProperty()); -// op.addResponse(String.valueOf(200), response); -// op.tag("Documentation"); -// Path p = new Path(); -// op.setSummary("Shows this swagger spec in a user interface"); -// p.setGet(op); -// r.getSwagger().path("/apix/v1/docs/ui", p); -// } -// -// public List getSchemes() { -// ArrayList ret = new ArrayList<>(); -// // This doesn't seem to work with the current setup at xenit, -// // using https://xxx.dev.xenit.eu gives me http protocol instead of https -// -// // So, always use https -// // Seems to work on 12/12/17, adding both. TODO: use from location instead of option -// ret.add(Scheme.HTTPS); -// ret.add(Scheme.HTTP); -// return ret; -// } -//} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java index 790720bf..d06d20a6 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java @@ -4,9 +4,6 @@ import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.version.IVersionService; import eu.xenit.apix.version.VersionDescription; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -22,8 +19,6 @@ public GeneralWebscript(IVersionService versionService) { } @GetMapping(value = "/v1/version") - @ApiOperation("Access the version information for Api-X") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = VersionDescription.class)) public ResponseEntity getApixVersion() { return writeJsonResponse(versionService.getVersionDescription()); } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkRequest.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkRequest.java index a4b62a2e..0b04e280 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkRequest.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkRequest.java @@ -1,18 +1,14 @@ package eu.xenit.apix.rest.v1.bulk; import com.fasterxml.jackson.databind.JsonNode; -import io.swagger.annotations.ApiModelProperty; /** * Represents a single request in a bulk requests call Created by kenneth on 18.03.16. */ public class BulkRequest { - @ApiModelProperty(required = true, allowableValues = "get,put,post,delete") private String method; - @ApiModelProperty(example = "/version?alf_ticket=TICKET_4654...", required = true) private String url; - @ApiModelProperty(dataType = "object", notes = "Only allowed for PUT and POST") private JsonNode body; public BulkRequest() { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkSubResult.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkSubResult.java index 61782ca4..4a21f2e3 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkSubResult.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkSubResult.java @@ -1,7 +1,6 @@ package eu.xenit.apix.rest.v1.bulk; import com.fasterxml.jackson.databind.JsonNode; -import io.swagger.annotations.ApiModelProperty; import java.util.HashMap; import java.util.Map; @@ -10,9 +9,7 @@ */ public class BulkSubResult { - @ApiModelProperty(value = "The HTTP status code of the sub call", example = "200") private int statusCode; - @ApiModelProperty(value = "JSON result body of the sub call", dataType = "object") private JsonNode body; private Map headers; diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java index fba65980..19cca618 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java @@ -4,9 +4,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -40,8 +37,6 @@ public BulkWebscript1(ServiceRegistry serviceRegistry, } @PostMapping(value = "/v1/bulk") - @ApiOperation("Performs multiple Api-X operations in a single rest call") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = BulkSubResult[].class)) public ResponseEntity bulk(@RequestBody final BulkRequest[] bulkRequests, final WebScriptRequest req) throws IOException { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java index 55f5f8d4..71bd235a 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java @@ -6,9 +6,6 @@ import eu.xenit.apix.categories.ICategoryService; import eu.xenit.apix.data.QName; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import java.util.List; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -26,8 +23,6 @@ public CategoryWebScript1(ICategoryService categoryService) { } @GetMapping(value = "/v1/category/aspect/{qname}") - @ApiOperation(value = "Return the categories available for an aspect") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Categories.class)) public ResponseEntity getCategoriesForAspect(@PathVariable final String qname) { QName apixQName = new QName(qname); List categories = categoryService.getCategoryTree(apixQName); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java index efeed318..6e4dbef2 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java @@ -9,10 +9,6 @@ import eu.xenit.apix.configuration.ConfigurationService; import eu.xenit.apix.configuration.Configurations; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import java.io.IOException; import java.util.Arrays; @@ -49,20 +45,11 @@ public ConfigurationWebscript1( @GetMapping(value = "/v1/configuration", consumes = {"application/js"}, produces = {"application/js"}) - @ApiOperation("Returns configuration files information and content") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Configurations.class)) public ResponseEntity getJsConfigurationFiles( - @RequestParam(defaultValue = "content,nodeRef", required = false) - @ApiParam( - value = "Comma separated field names to include.", - defaultValue = "content,nodeRef", - allowableValues = "content,nodeRef,path,metadata,parsedContent") String[] fields, - @RequestParam @ApiParam("The directory to search for configuration files, relative to the data dictionary") - String searchDirectory, - @RequestParam(value = "filter.name", required = false) - @ApiParam(name = "filter.name", value = "Regular expression that the node name should match.") - String nameFilter, - @RequestParam(required = false) @ApiParam("Javascript callback function") String callback + @RequestParam(defaultValue = "content,nodeRef", required = false) String[] fields, + @RequestParam String searchDirectory, + @RequestParam(value = "filter.name", required = false) String nameFilter, + @RequestParam(required = false) String callback ) throws IOException { List fieldsList = Arrays.asList(fields); ConfigurationFileFlags configurationFileFlags = new ConfigurationFileFlags( @@ -83,21 +70,10 @@ public ResponseEntity getJsConfigurationFiles( @GetMapping(value = "/v1/configuration" , consumes = {MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_JSON_VALUE}) - @ApiOperation("Returns configuration files information and content") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Configurations.class)) public ResponseEntity getConfigurationFiles( - @RequestParam(defaultValue = "content,nodeRef", required = false) - @ApiParam( - value = "Comma separated field names to include.", - defaultValue = "content,nodeRef", - allowableValues = "content,nodeRef,path,metadata,parsedContent") - String[] fields, - @RequestParam - @ApiParam("The directory to search for configuration files, relative to the data dictionary") - String searchDirectory, - @RequestParam(value = "filter.name", required = false) - @ApiParam(name = "filter.name", value = "Regular expression that the node name should match.") - String nameFilter + @RequestParam(defaultValue = "content,nodeRef", required = false) String[] fields, + @RequestParam String searchDirectory, + @RequestParam(value = "filter.name", required = false) String nameFilter ) throws IOException { List fieldsList = Arrays.asList(fields); ConfigurationFileFlags configurationFileFlags = new ConfigurationFileFlags( diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java index 4bf748f7..021c431e 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java @@ -12,9 +12,6 @@ import eu.xenit.apix.properties.Properties; import eu.xenit.apix.properties.PropertyDefinition; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; @@ -38,8 +35,6 @@ public DictionaryWebScript1( } @GetMapping(value = "/v1/dictionary/properties/**") - @ApiOperation(value = "Return the definition of a property") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = PropertyDefinition.class)) public ResponseEntity getPropertyDefinition(HttpServletRequest request) { QName qname = extractQNameFromUrlPath(request, "/v1/dictionary/properties/"); PropertyDefinition propDef = dictionaryService.GetPropertyDefinition(qname); @@ -50,16 +45,12 @@ public ResponseEntity getPropertyDefinition(HttpServletRequest request) { } @GetMapping(value = "/v1/dictionary/properties") - @ApiOperation(value = "Return properties") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Properties.class)) public ResponseEntity getProperties() { return writeJsonResponse(dictionaryService.getProperties()); } @GetMapping(value = "/v1/dictionary/types") - @ApiOperation(value = "Return the definitions of types") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Types.class)) public ResponseEntity getSubTypeDefinitions(@RequestParam(defaultValue = "sys:base", required = false) final String parent) { return writeJsonResponse( @@ -70,10 +61,6 @@ public ResponseEntity getSubTypeDefinitions(@RequestParam(defaultValue = } @GetMapping(value = "/v1/dictionary/types/**") - @ApiOperation(value = "Return the definition of a type") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success", response = TypeDefinition.class), - @ApiResponse(code = 404, message = "Not Found")}) public ResponseEntity getTypeDefinition(HttpServletRequest request) { QName qname = extractQNameFromUrlPath(request, "/v1/dictionary/types/"); logger.debug("Received type qname {}", qname); @@ -85,8 +72,6 @@ public ResponseEntity getTypeDefinition(HttpServletRequest request) { } @GetMapping(value = "/v1/dictionary/aspects/**") - @ApiOperation(value = "Return the definition of a aspect") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = AspectDefinition.class)) public ResponseEntity getAspectDefinition(HttpServletRequest request) { QName qname = extractQNameFromUrlPath(request, "/v1/dictionary/aspects/"); logger.debug("Received aspect qname {}", qname); @@ -97,17 +82,12 @@ public ResponseEntity getAspectDefinition(HttpServletRequest request) { return writeJsonResponse(classDef); } - @GetMapping(value = "/v1/dictionary/aspects") - @ApiOperation(value = "Return apects") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Aspects.class)) public ResponseEntity getAspects() { return writeJsonResponse(dictionaryService.getAspects()); } @GetMapping(value = "/v1/dictionary/namespaces") - @ApiOperation(value = "Returns the namespaces") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Namespaces.class)) public ResponseEntity getNamespaces() { return writeJsonResponse(dictionaryService.getNamespaces()); } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java index 880e881e..541a9ba4 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java @@ -2,14 +2,12 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModelProperty; /** * Created by Michiel Huygen on 12/05/2016. */ class ChangeParentOptions { - @ApiModelProperty(required = true) public String parent; @JsonCreator diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateAssociationOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateAssociationOptions.java index ae15659e..a9c36e15 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateAssociationOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateAssociationOptions.java @@ -2,16 +2,13 @@ import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.data.QName; -import io.swagger.annotations.ApiModelProperty; /** * Created by Michiel Huygen on 23/05/2016. */ public class CreateAssociationOptions { - @ApiModelProperty(required = true) private NodeRef target; - @ApiModelProperty("Defaults to cm:content") private QName type = new QName("{http://www.alfresco.org/model/content/1.0}content"); public NodeRef getTarget() { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java index 080b1f2d..d2e76fa4 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; import eu.xenit.apix.data.QName; -import io.swagger.annotations.ApiModelProperty; import java.util.HashMap; import java.util.Map; import org.alfresco.model.ContentModel; @@ -15,7 +14,6 @@ public class CreateNodeOptions { public static final QName PROP_NAME_QNAME = new QName(ContentModel.PROP_NAME.toString()); - @ApiModelProperty(required = true) public String parent; public String name; public String type; diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java index 119bce8c..c5cc549b 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java @@ -2,11 +2,9 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModelProperty; class InheritFromParent { - @ApiModelProperty(required = true) private boolean inheritFromParent; @JsonCreator diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java index 1b4e45ac..55696fce 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java @@ -21,11 +21,6 @@ import eu.xenit.apix.permissions.PermissionValue; import eu.xenit.apix.rest.v1.ApixV1Webscript; import eu.xenit.apix.rest.v1.nodes.ChangeAclsOptions.Access; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; @@ -77,42 +72,6 @@ public NodesWebscript1(INodeService nodeService, IPermissionService permissionSe } @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/metadata") - @ApiOperation(value = "Change node metadata", - notes = "Example to set a node's title and add the sys:versionable aspect:\n" + - "\n" + - "```\n" + - "POST /apix/v1/nodes/workspace/SpacesStore/b54287de-381e-44b1-b6d1-e6c9a9d632fd/metadata\n" + - "{\n" + - " \"aspectsToAdd\": [\"{http://www.alfresco.org/model/system/1.0}temporary\"],\n" + - " \"propertiesToSet\": {\"{http://www.alfresco.org/model/content/1.0}title\":[\"My new title\"]}\n" - + - "}\n" + - "```\n" + - "\n" + - "When you generalize the type of a node instead of specializing, the default properties of the " + - "initial **type** that are not present in the new type are removed, however, the default aspects " + - "are not. This is the default behaviour. If you also want to remove these aspects on type " + - "generalization, add the parameter **cleanUpAspectsOnGeneralization** to the request body.\n" + - "\n" + - "Example for cleaning up aspects on type generalization:\n" + - "\n" + - "```\n" + - "POST /apix/v1/nodes/workspace/SpacesStore/b54287de-381e-44b1-b6d1-e6c9a9d632fd/metadata\n" + - "{\n" + - " \"type\": \"{http://www.alfresco.org/model/content/1.0}content\",\n" + - " \"cleanUpAspectsOnGeneralization\": true\n" + - "}\n" + - "```\n" + - "\n" + - "Changing the cm:name property will also update the qname path " + - "of the node so it is in sync with it.\n" - + - "This only applies to nodes of type or subtype cm:content or cm:folder " + - "but not of type or subtype of cm:systemfolder.") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success", response = NodeMetadata.class), - @ApiResponse(code = 403, message = "Not Authorized") - }) public ResponseEntity setMetadata(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid, @RequestBody final MetadataChanges changes) { NodeRef nodeRef = createNodeRef(space, store, guid); @@ -123,12 +82,7 @@ public ResponseEntity setMetadata(@PathVariable final String space return writeJsonResponse(nodeMetadata); } - @ApiOperation("Retrieve node metadata") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/metadata") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success", response = NodeMetadata.class), - @ApiResponse(code = 403, message = "Not Authorized") - }) public ResponseEntity getMetadata(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { NodeMetadata nodeMetadata = nodeService.getMetadata( @@ -142,11 +96,7 @@ public ResponseEntity getMetadata(@PathVariable String space, @Pat } - @ApiOperation("Delete a node") @DeleteMapping(value = "/v1/nodes/{space}/{store}/{guid}") - @ApiResponses({@ApiResponse(code = 200, message = "Success"), - @ApiResponse(code = 403, message = "Not Authorized"), - @ApiResponse(code = 404, message = "Not Found")}) public ResponseEntity deleteNode(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid, @RequestParam(required = false) final String permanently) { @@ -164,12 +114,7 @@ public ResponseEntity deleteNode(@PathVariable final String space, @Path .body(String.format("Failed to delete node, node does not exist: %s", nodeRef.toString())); } - @ApiOperation("Retrieve node associations.\n" + - "Versionstore does not support sourceAssocs. " + - "For version nodes, an empty list is returned for this component of the result.") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations") - @ApiResponses({@ApiResponse(code = 200, message = "Success", response = NodeAssociations.class), - @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity getAssociations(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { return writeJsonResponse( @@ -179,10 +124,7 @@ public ResponseEntity getAssociations(@PathVariable String spa ); } - @ApiOperation("Create new association with given node as source") @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations") - @ApiResponses({@ApiResponse(code = 200, message = "Success"), - @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity createAssociation(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestBody CreateAssociationOptions options) { @@ -194,9 +136,7 @@ public ResponseEntity createAssociation(@PathVariable String space, @PathV return ResponseEntity.ok().build(); } - @ApiOperation("Deletes an association with given node as source") @DeleteMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations") - @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity deleteAssociation(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestParam NodeRef target, @RequestParam String type) { @@ -209,10 +149,7 @@ public ResponseEntity deleteAssociation(@PathVariable String space, @PathV } - @ApiOperation("Retrieve node parent associations") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations/parents") - @ApiResponses({@ApiResponse(code = 200, message = "Success", response = ChildParentAssociation[].class), - @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity> getParentAssociations(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -223,10 +160,7 @@ public ResponseEntity> getParentAssociations(@PathV ); } - @ApiOperation("Retrieve node child associations") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations/children") - @ApiResponses({@ApiResponse(code = 200, message = "Success", response = ChildParentAssociation[].class), - @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity> getChildAssociations(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -237,10 +171,7 @@ public ResponseEntity> getChildAssociations(@PathVa ); } - @ApiOperation("Retrieve node peer associations with given node being the source") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations/targets") - @ApiResponses({@ApiResponse(code = 200, message = "Success", response = NodeAssociation[].class), - @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity> getSourcePeerAssociations(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -251,13 +182,7 @@ public ResponseEntity> getSourcePeerAssociations(@PathVari ); } - @ApiOperation(value = "Retrieve current user's permissions for a node", - notes = "Returns a key-value map of permissions keys to a value of 'DENY' or 'ALLOW'. " + - "Possible keys are: Read, Write, Delete, CreateChildren, ReadPermissions, ChangePermissions, " + - "or custom permissions") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/permissions") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success", response = PermissionValue.class, responseContainer = "Map")}) // It would seem permissions can always be retrieved? public ResponseEntity> getPermissions(@PathVariable String space, @PathVariable String store, @@ -269,9 +194,7 @@ public ResponseEntity> getPermissions(@PathVariable ); } - @ApiOperation(value = "sets a user a permission for a node.") @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/permissions/authority/{authority}/permission/{permission}") - @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity setPermission(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @PathVariable String authority, @PathVariable String permission) { @@ -281,9 +204,7 @@ public ResponseEntity setPermission(@PathVariable String space, @PathVaria return ResponseEntity.ok().build(); } - @ApiOperation(value = "removes a user its permission for a node.") @DeleteMapping(value = "/v1/nodes/{space}/{store}/{guid}/permissions/authority/{authority}/permission/{permission}") - @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity deletePermission(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @PathVariable String authority, @PathVariable String permission) { @@ -291,10 +212,7 @@ public ResponseEntity deletePermission(@PathVariable String space, @PathVa return ResponseEntity.ok().build(); } - @ApiOperation(value = "Gets the ACLs for a node.") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/acl") - @ApiResponses({@ApiResponse(code = 200, message = "Success", response = NodePermission.class), - @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity getAcls(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { return writeJsonResponse( @@ -305,7 +223,6 @@ public ResponseEntity getAcls(@PathVariable String space, @PathV } @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/acl/inheritFromParent") - @ApiResponses({@ApiResponse(code = 403, message = "Not Authorized")}) public void setInheritParentPermissions(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestBody final InheritFromParent inherit) { this.permissionService.setInheritParentPermissions( @@ -313,21 +230,7 @@ public void setInheritParentPermissions(@PathVariable String space, @PathVariabl ); } - @ApiOperation(value = "Sets the ACL for a node.", notes = "Example:\n" + - "\n" + - "```\n" + - "{\n" + - " \"inheritFromParent\": false,\n" + - " \"ownAccessList\": [\n" + - " {\n" + - " \"allowed\": true,\n" + - " \"authority\": \"MYGROUP\",\n" + - " \"permission\": \"Collaborator\"\n" + - " }\n" + - "]}\n" + - "```", consumes = "application/json") @PutMapping(value = "/v1/nodes/{space}/{store}/{guid}/acl") - @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity setAcls(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestBody final ChangeAclsOptions changeAclsOptions) { @@ -352,10 +255,7 @@ public ResponseEntity setAcls(@PathVariable String space, @PathVariable St return ResponseEntity.ok().build(); } - @ApiOperation("Returns path of the node") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/path") - @ApiResponses({@ApiResponse(code = 200, message = "Success", response = NodePath.class), - @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity getPath(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { return writeJsonResponse( @@ -365,15 +265,7 @@ public ResponseEntity getPath(@PathVariable String space, @PathVariabl ); } - @ApiOperation("Returns combined information of a node.\n" + - "Note: versionstore does not support sourceAssocs. " + - "For version nodes, an empty list added to the result") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success", response = NodeInfo.class), - @ApiResponse(code = 403, message = "Not Authorized"), - @ApiResponse(code = 404, message = "Not Found") - }) public ResponseEntity getAllInfoOfNode(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { try { @@ -397,49 +289,7 @@ public ResponseEntity getAllInfoOfNode(@PathVariable String space, @Path } } - @ApiOperation(value = "Returns combined information of multiple nodes. " - + "Nodes errors or without appropriate permissions will not be included in return, " - + "and will not cause failure of the call.", - notes = "Example to get combined information of multiple nodes:\n" + - "\n" + - "```\n" + - "POST /apix/v1/nodes/nodeInfo\n" + - "{\n" + - "\"retrieveMetadata\" : true, \n" + - "\"retrievePath\" : true, \n" + - "\"retrievePermissions\" : true, \n" + - "\"retrieveAssocs\" : true, \n" + - "\"retrieveChildAssocs\" : true, \n" + - "\"retrieveParentAssocs\" : true, \n" + - "\"retrieveTargetAssocs\" : true, \n" + - "\"noderefs\": [ \n" + - " \"workspace://SpacesStore/123456789\", \n" + - " \"workspace://SpacesStore/147258369\", \n" + - " \"workspace://SpacesStore/478159236\" \n" + - "]}\n" + - "```" + - "\n" + - "'retrieveMetadata', 'retrievePath', 'retrievePermissions', " + - "'retrieveAssocs', 'retrieveChildAssocs',\n" - + - "'retrieveParentAssocs', 'retrieveTargetAssocs' are optional parameters.\n" + - "Set 'retrieveMetadata' to false to omit the aspects and properties from the result.\n" + - "Set 'retrievePath' to false to omit the path from the result.\n" + - "Set 'retrievePermissions' to false to omit the permissions from the result.\n" + - "Set 'retrieveAssocs' to false to omit the associations(parent associations, child associations, " + - "peer associations) from the result.\n" - + - "Set 'retrieveChildAssocs' to false to omit the child associations from the result.\n" + - "Set 'retrieveParentAssocs' to false to omit the parent associations from the result.\n" + - "Set 'retrieveTargetAssocs' to false to omit the peer target associations from the result.\n" + - "Set 'retrieveSourceAssocs' to false to omit the peer source associations from the result. " + - "Note: versionstore does not support sourceAssocs. " + - "For version nodes, an empty list added to the result\n") @PostMapping(value = "/v1/nodes/nodeInfo") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success", response = NodeInfo[].class), - @ApiResponse(code = 400, message = "Bad Request") - }) // TODO @Zlatin MVC Pojo public ResponseEntity getAllInfoOfNodes(@RequestBody final String requestString) { logger.debug("request content: {}", requestString); @@ -512,13 +362,7 @@ public ResponseEntity getAllInfoOfNodes(@RequestBody final String reques return writeJsonResponse(nodeInfoList); } - @ApiOperation(value = "Retrieves the ancestors of the nodes", - notes = "It is possible to add \"root\" as a request parameter.\n" - + "It is the node reference up to which point ancestors will be retrieved.\n" - + "The default root reference will be the reference of Company Home") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/ancestors") - @ApiResponses({@ApiResponse(code = 200, message = "Success", response = AncestorsObject.class), - @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity retrieveAncestors(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestParam(required = false) String root) { @@ -543,40 +387,7 @@ public ResponseEntity retrieveAncestors(@PathVariable String space, @Pat } } - @ApiOperation(value = "Creates or copies a node", - notes = "Example of POST body:\n" - + "\n" - + "```\n" - + "POST /apix/v1/nodes\n" - + "{\n" - + "\"parent\" : \"workspace://SpacesStore/d5dac928-e581-4507-9be7-9a2416adc318\", \n" - + "\"name\" : \"mydocument.txt\", \n" - + "\"type\" : \"{http://www.alfresco.org/model/content/1.0}content\", \n" - + "\"properties\" : {\n" - + " \"{namespace}property1\": [\n" - + " \"string\"\n" - + " ],\n" - + " \"{namespace}property2\": [\n" - + " \"string\"\n" - + " ],\n" - + " \"{namespace}property3\": [\n" - + " \"string\"\n" - + " ]\n" - + "}, \n" - + "\"aspectsToAdd\" : [\n" - + " \"{namespace}aspect1\"\n" - + "], \n" - + "\"aspectsToRemove\" : [\n" - + " \"{namespace}aspect1\"\n" - + "], \n" - + "\"copyFrom\" : \"workspace://SpacesStore/f0d15919-3841-4170-807f-b81d2ebdeb80\", \n" - + "}\n" - + "```" - + "\n" - + "\"aspectsToRemove\" is only relevant when copying a node.\n") @PostMapping(value = "/v1/nodes") - @ApiResponses({@ApiResponse(code = 200, message = "Success", response = NodeInfo.class), - @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity createNode(@RequestBody final CreateNodeOptions createNodeOptions) { try { Object resultObject = serviceRegistry.getRetryingTransactionHelper() @@ -638,9 +449,7 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions } } - @ApiOperation("Moves a node by changing its parent") @PutMapping(value = "/v1/nodes/{space}/{store}/{guid}/parent") - @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity setParent(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid, @RequestBody ChangeParentOptions location) { NodeRef nodeToMove = createNodeRef(space, store, guid); @@ -659,13 +468,7 @@ public ResponseEntity setParent(@PathVariable final String space, @Path } } - @ApiOperation(value = "Retrieves all comments for a given node") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/comments") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success"), - @ApiResponse(code = 403, message = "Not Authorized"), - @ApiResponse(code = 404, message = "Not Found") - }) public ResponseEntity getComments(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestParam(defaultValue = "0") int skipcount, @RequestParam(defaultValue = "10") int pagesize) { @@ -682,13 +485,7 @@ public ResponseEntity getComments(@PathVariable String space, @PathVariable S return writeNotAuthorizedResponse(new AccessDeniedException(target.getValue())); } - @ApiOperation(value = "Appends a new comment to the given node.") @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/comments") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success"), - @ApiResponse(code = 403, message = "Not Authorized"), - @ApiResponse(code = 404, message = "Not Found") - }) public ResponseEntity addComment(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestBody final Comment newComment) { final NodeRef target = this.createNodeRef(space, store, guid); @@ -699,13 +496,7 @@ public ResponseEntity addComment(@PathVariable String space, @PathVariable St return writeJsonResponse(responseComment); } - @ApiOperation(value = "Returns the comment with the given id.") @GetMapping(value = "/v1/comments/{space}/{store}/{guid}") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success"), - @ApiResponse(code = 403, message = "Not Authorized"), - @ApiResponse(code = 404, message = "Not Found") - }) public ResponseEntity getComment(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { final NodeRef targetComment = this.createNodeRef(space, store, guid); @@ -720,13 +511,7 @@ public ResponseEntity getComment(@PathVariable String space, @PathVariable St } } - @ApiOperation(value = "Updates the comment with the given id.") @PutMapping(value = "/v1/comments/{space}/{store}/{guid}") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success"), - @ApiResponse(code = 403, message = "Not Authorized"), - @ApiResponse(code = 404, message = "Not Found") - }) public ResponseEntity updateComment(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestBody final Comment newComment) { final NodeRef targetComment = this.createNodeRef(space, store, guid); @@ -737,13 +522,7 @@ public ResponseEntity updateComment(@PathVariable String space, @PathVariable return writeJsonResponse(updatedComment); } - @ApiOperation(value = "Deletes the comment with the given id.") @DeleteMapping(value = "/v1/comments/{space}/{store}/{guid}") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success"), - @ApiResponse(code = 403, message = "Not Authorized"), - @ApiResponse(code = 404, message = "Not Found") - }) public ResponseEntity deleteComment(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { final NodeRef targetComment = this.createNodeRef(space, store, guid); @@ -754,12 +533,7 @@ public ResponseEntity deleteComment(@PathVariable String space, @PathVariable return writeJsonResponse(String.format("Comment %s deleted", targetComment)); } - @ApiOperation(value = "Downloads content file for given node") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/content") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success"), - @ApiResponse(code = 403, message = "Not Authorized"), - @ApiResponse(code = 404, message = "Not Found")}) public ResponseEntity getContent(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { final NodeRef nodeRef = this.createNodeRef(space, store, guid); ContentInputStream contentInputStream = nodeService.getContent(nodeRef); @@ -770,11 +544,7 @@ public ResponseEntity getContent(@PathVariable String space, @PathVariable St .body(new InputStreamResource(contentInputStream.getInputStream())); } - @ApiOperation(value = "Sets or updates the content for given node. " + - "If no file is given the content will be set to empty.", consumes = "multipart/form-data") @PutMapping(value = "/v1/nodes/{space}/{store}/{guid}/content") - @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) - @ApiImplicitParams({@ApiImplicitParam(name = "file", paramType = "form", dataType = "file")}) public ResponseEntity setContent(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestPart final MultipartFile file) { final NodeRef finalDestination = this.createNodeRef(space, store, guid); @@ -789,9 +559,7 @@ public ResponseEntity setContent(@PathVariable String space, @PathVariable } - @ApiOperation(value = "Sets the content for given node to empty") @DeleteMapping(value = "/v1/nodes/{space}/{store}/{guid}/content") - @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity deleteContent(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { RetryingTransactionHelper transactionHelper = serviceRegistry.getRetryingTransactionHelper(); @@ -804,9 +572,7 @@ public ResponseEntity deleteContent(@PathVariable String space, @PathVaria } - @ApiOperation(value = "Checks if the given node exists") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/exists") - @ApiResponses({@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 403, message = "Not Authorized")}) public ResponseEntity exists(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { return writeJsonResponse( @@ -817,22 +583,7 @@ public ResponseEntity exists(@PathVariable String space, @PathVariable } - @ApiOperation(value = "Creates a new node with given content", consumes = "multipart/form-data") @PostMapping(value = "/v1/nodes/upload") - @ApiResponses({@ApiResponse(code = 200, message = "Success", response = NodeInfo.class), - @ApiResponse(code = 403, message = "Not Authorized")}) - @ApiImplicitParams({ - @ApiImplicitParam(value = "Noderef of parent for the new node", name = "parent", paramType = "form", - dataType = "string", required = true), - //TODO: Datatype doesnt work here? - @ApiImplicitParam(value = "QName type for the new node", name = "type", paramType = "form", - dataType = "string"), - @ApiImplicitParam(name = "file", paramType = "form", dataType = "file", required = true), - @ApiImplicitParam(value = "Metadata for this file", name = "metadata", paramType = "form", - dataType = "string"), - @ApiImplicitParam(value = "Enable metadata extraction from the content, for example for msg files", - name = "extractMetadata", paramType = "form", dataType = "boolean"), - }) // TODO @Zlatin MVC Pojo public ResponseEntity uploadNode( @RequestPart(required = false) String type, diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java index 65927350..2e54e488 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java @@ -5,9 +5,6 @@ import eu.xenit.apix.people.IPeopleService; import eu.xenit.apix.people.Person; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import java.util.NoSuchElementException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,8 +26,6 @@ public PeopleWebscript1(IPeopleService personService) { } @GetMapping(value = "/v1/people/{space}/{store}/{guid}") - @ApiOperation(value = "Returns person information") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Person.class)) public ResponseEntity getPerson(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid) { @@ -51,8 +46,6 @@ public ResponseEntity getPerson(@PathVariable final String space, } @GetMapping(value = "/v1/people") - @ApiOperation(value = "Returns person information given a userName", notes = "") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Person.class)) public ResponseEntity getPersonViaUserName(@RequestParam final String userName) { logger.debug("Asked person with name: {}", userName); try{ diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java index f39fcffa..3c1944d3 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java @@ -6,9 +6,6 @@ import eu.xenit.apix.dictionary.properties.IPropertyService; import eu.xenit.apix.properties.PropertyDefinition; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -30,8 +27,6 @@ public PropertiesWebScript1(IPropertyService propertyService) { } @GetMapping(value = "/v1/properties/{qname}") - @ApiOperation(value = "Return the definition of a property", notes = "") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = PropertyDefinition.class)) //Use qname with slash to avoid //https://stackoverflow.com/questions/13482020/encoded-slash-2f-with-spring-requestmapping-path-param-gives-http-400 public ResponseEntity getPropertyDefinition(@PathVariable final QName qname, diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java index 2bf6b19d..8d0cb80c 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java @@ -5,12 +5,6 @@ import eu.xenit.apix.rest.v1.ApixV1Webscript; import eu.xenit.apix.search.ISearchService; import eu.xenit.apix.search.SearchQuery; -import eu.xenit.apix.search.SearchQueryResult; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -27,118 +21,6 @@ public SearchWebScript1(ISearchService service) { } @PostMapping(value = "/v1/search") - @ApiOperation(value = "Performs a search for nodes", notes ="# Request components\n" - + "\n" - + "## query\n" - + "Object containing subcomponents that build the requested query.\n" - + "Info about the Search query syntax can be found here: " + - "https://docs.xenit.eu/alfred-api/stable-user/rest-api\n" - + "### special search terms:\n" - + "- type: searches for nodes of that type (for example: \"type\" : \"cm:content\")\n" - + "- aspect: searches for nodes with that aspect (for example: \"aspect\" : \"cm:titled\")\n" - + "- noderef: searches the node with that noderef (for example: \"noderef\" :" + - " \"workspace://SpacesStore/f0d15919-3841-4170-807f-b81d2ebdeb80\")\n" - + "- parent: searches the nodes with that parent (for example: \"parent\" : " + - "\"workspace://SpacesStore/f0d15919-3841-4170-807f-b81d2ebdeb80\")\n" - + "- path: searches the nodes with that path (for example: \"path\" : \"/\")\n" - + "- category: searches the nodes with that category (for example: \"category\" : " + - "\"workspace://SpacesStore/f0d15919-3841-4170-807f-b81d2ebdeb80\")\n" - + "- text: searches the nodes with content containing that text (for example: \"text\" : \"this text\")\n" - + "- all: searches the nodes with content, cm:name, cm:creator, cm:modifier or cm:author containing " + - "the value (for example: \"all\" : \"search term\")\n" - + "- isunset: searches the nodes with where the value of the property is not set (for example: " + - "\"isunset\" : \"cm:author\")\n" - + "- isnull: searches the nodes with where the value of the property is null (for example: \"isnull\" :" + - " \"cm:author\")\n" - + "- isnotnull: searches the nodes with where the value of the property is not null (for example: " + - "\"isnotnull\" : \"cm:author\")\n" - + "- exists: searches the nodes that have the property (for example: \"exists\" : \"cm:author\")\n" - + "\n" - + "## paging\n" - + "`Optional`\n" - + "\n" - + "Options to skip over results starting from the top of the result and " + - "to limit the total number of results.\n" - + "\n" - + "## facets\n" - + "`Optional`\n" - + "\n" - + "Options to enable, limit the total amount, minimum number of hits and customize input of facets.\n" - + "\n" - + "Note: facets with 0 hits are not returned in the result\n" - + "\n" - + "## orderBy\n" - + "`Optional`\n" - + "\n" - + "Options to select the property to order by and the direction of sorting.\n" - + "\n" - + "## consistency\n" - + "`Optional`\n" - + "\n" - + "Option to request specific consistency\n" - + "\n" - + "## locale\n" - + "`Optional`\n" - + "\n" - + "Options to request specific locale and encoding options\n" - + "\n" - + "## workspace\n" - + "`Optional`\n" - + "\n" - + "Options to change the target alfresco workspace\n" - + "\n" - + "## highlight\n" - + "`5.2 and up`\n" - + "\n" - + "`Optional`\n" - + "\n" - + "Options to change the highlight configuration.\n" - + "Minimal requirement is the `fields` array, which takes object containing at least the `field` property. " + - "Each list element specifies a property on which higlighting needs to be applied. " + - "When no fields are specified, the call defaults to `cm:content` as field.\n" - + "Full documentation can be found on the alfresco " + - "[documentation](https://docs.alfresco.com/5.2/concepts/search-api-highlight.html) page.\n" - + "\n" - + "# Examples\n" - + "\n" - + "Search for the first 10 nodes in the `cm:content` namespace:\n" - + "```json\n" - + "{\n" - + " \"query\": {\"type\":\"{http://www.alfresco.org/model/content/1.0}content\"},\n" - + " \"paging\": {\n" - + " \"limit\": 10,\n" - + " \"skip\": 0\n" - + " },\n" - + " \"facets\": {\n" - + " \"enabled\": false\n" - + " }\n" - + "}\n" - + "```\n" - + "\n" - + "Search for all nodes with the term 'budget' in the `cm:content` property (fulltext), and show two " + - "highlighted hits with delimiter \\\\:\n" - + "```json\n" - + "{\n" - + " \"query\": {\n" - + " \"property\": {\n" - + " \"exact\": false,\n" - + " \"name\": \"cm:content\",\n" - + " \"value\": \"budget\"\n" - + " }\n" - + " },\n" - + " \"highlight\":{\n" - + " \"prefix\":\"\",\n" - + " \"postfix\":\"\",\n" - + " \"snippetCount\":2,\n" - + "\t\t\"fields\":[{\"field\":\"cm:content\"}]\n" - + " }\n" - + "}\n" - + "```") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success", response = SearchQueryResult.class), - @ApiResponse(code = 400, message = "Failure")}) - @ApiImplicitParams({ - @ApiImplicitParam(dataType = "eu.xenit.apix.search.SearchQuery", paramType = "body", name = "body")}) public ResponseEntity execute(@RequestBody final SearchQuery query) { try { return writeJsonResponse(service.query(query)); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java index 63137484..8967a86d 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java @@ -9,9 +9,6 @@ import eu.xenit.apix.rest.v1.nodes.NodeInfo; import eu.xenit.apix.sites.ISite; import eu.xenit.apix.sites.ISiteService; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import java.util.ArrayList; import java.util.List; import org.alfresco.service.ServiceRegistry; @@ -49,21 +46,7 @@ public SitesWebscript1(INodeService nodeService, IPermissionService permissionSe this.serviceRegistry = serviceRegistry; } - @ApiOperation(value = "Retrieves information about the available sites of the current user", - notes = "Returns a list of sites. For each site the node reference, short name, title, description,\n" - + "site visibility and list of site components (document libray, links, data lists, wiki,\n" - + "discussions) are returned.\n" - + "\n" - + "There are no mandatory request parameters. However, there are optional ones:\n" - + "Set 'retrieveMetadata' to true to return the aspects and properties of the sites.\n" - + "Set 'retrievePath' to true to return the path of the sites.\n" - + "Set 'retrievePermissions' to true to return the permissions of the sites.\n" - + "Set 'retrieveChildAssocs' to true to return the child associations of the sites.\n" - + "Set 'retrieveParentAssocs' to true to return the parent associations of the sites.\n" - + "Set 'retrieveTargetAssocs' to true to return the target peer associations of the sites.\n" - + "Set 'retrieveSourceAssocs' to true to return the source peer associations of the sites.\n") @GetMapping(value = "/v1/sites/mySites") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = SiteInfo[].class)) public ResponseEntity> getMySites( @RequestParam(required = false, defaultValue = "false") Boolean retrieveMetadata, @RequestParam(required = false, defaultValue = "false") boolean retrievePath, diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java index 33997573..5f02d19f 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java @@ -3,7 +3,6 @@ import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import io.swagger.annotations.Api; import java.io.File; import java.io.IOException; import org.springframework.core.env.Environment; @@ -14,7 +13,6 @@ import org.springframework.web.bind.annotation.RestController; -@Api(hidden = true) @RestController("eu.xenit.apix.rest.v1.temp.LogsWebscript") public class LogsWebscript extends ApixV1Webscript { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java index 972b5380..42eb379c 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java @@ -3,11 +3,6 @@ import eu.xenit.apix.WIP.IWIPService; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -23,10 +18,7 @@ public WIPWebscript(IWIPService wipService) { this.wipService = wipService; } - @ApiOperation(value = "Downloads preview file for given node") @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/content/previews/pdf") - @ApiResponses(@ApiResponse(code = 200, message = "Success")) - @ApiImplicitParams({@ApiImplicitParam(name = "file", paramType = "form", dataType = "file", required = true)}) public ResponseEntity getPreviewPdf(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java index d78f5d00..c9c4544a 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java @@ -3,9 +3,6 @@ import eu.xenit.apix.rest.v1.ApixV1Webscript; import eu.xenit.apix.translation.ITranslationService; import eu.xenit.apix.translation.Translations; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import java.util.Locale; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -22,8 +19,6 @@ public TranslationsWebscript1(ITranslationService translationService) { } @GetMapping(value = "/v1/translations/{locale}/checksum") - @ApiOperation("Retrieve a checksum of all translations for given locale") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = TranslationChecksum.class)) public ResponseEntity getChecksum(@PathVariable final String locale) { Locale language = Locale.forLanguageTag(locale); Long checksum = translationService.getTranslationsCheckSum(language); @@ -32,8 +27,6 @@ public ResponseEntity getChecksum(@PathVariable final Strin } @GetMapping(value = "/v1/translations/{locale}") - @ApiOperation("Get all available translations for given locale") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Translations.class)) public ResponseEntity getTranslations(@PathVariable final String locale) { Locale language = Locale.forLanguageTag(locale); Translations translations = translationService.getTranslations(language); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java index d6f72bb0..d5fa226b 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java @@ -7,11 +7,6 @@ import eu.xenit.apix.versionhistory.IVersionHistoryService; import eu.xenit.apix.versionhistory.Version; import eu.xenit.apix.versionhistory.VersionHistory; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import java.io.Serializable; import java.util.HashMap; @@ -46,8 +41,6 @@ public VersionHistoryWebScript1(IVersionHistoryService versionHistoryService) { } @GetMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/versions") - @ApiOperation(value = "Returns list of chronological version information for give node") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = VersionHistory.class)) public ResponseEntity getVersionHistory(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid) { @@ -58,8 +51,6 @@ public ResponseEntity getVersionHistory(@PathVariable final Stri } @GetMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/root") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Version.class)) - @ApiOperation(value = "Returns the root (oldest) version") public ResponseEntity getVersionHistoryRoot(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid) { @@ -69,8 +60,6 @@ public ResponseEntity getVersionHistoryRoot(@PathVariable final String } @GetMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/head") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Version.class)) - @ApiOperation(value = "Returns the head (newest) version") public ResponseEntity getVersionHistoryHead(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid) { @@ -80,10 +69,8 @@ public ResponseEntity getVersionHistoryHead(@PathVariable final String } @DeleteMapping(value = "/v1/versionhistory/{space}/{store}/{guid}") - @ApiResponses(@ApiResponse(code = 200, message = "Success")) //No method available to disable versioning. deleting will merely reset version history, // starting a new history upon a new version change - @ApiOperation(value = "Permanently emoves version history") public ResponseEntity deleteVersionHistory(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid) { @@ -92,11 +79,6 @@ public ResponseEntity deleteVersionHistory(@PathVariable final String space, } @PutMapping(value = "/v1/versionhistory/{space}/{store}/{guid}") - @ApiResponses(@ApiResponse(code = 200, message = "Success")) - @ApiImplicitParams({ - @ApiImplicitParam(dataType = "eu.xenit.apix.rest.v1.versionhistory.VersionOptions", - paramType = "body", name = "body")}) - @ApiOperation(value = "Enables versioning for this node, creating an initial version") public ResponseEntity setVersionHistory(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid, @@ -118,8 +100,6 @@ public ResponseEntity setVersionHistory(@PathVariable final String space, } @PostMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/versions/{label}/revert") - @ApiResponses(@ApiResponse(code = 200, message = "Success")) - @ApiOperation(value = "(Shallow) Revert the node to version with given label") public ResponseEntity revertVersionHistory(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid, @@ -129,8 +109,6 @@ public ResponseEntity revertVersionHistory(@PathVariable final String space, } @DeleteMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/versions/{label}") - @ApiResponses(@ApiResponse(code = 200, message = "Success")) - @ApiOperation(value = "Permanently remove version with given label") public ResponseEntity deleteVersion(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid, diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/CheckoutBody.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/CheckoutBody.java index d764c641..2ccb63f9 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/CheckoutBody.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/CheckoutBody.java @@ -3,17 +3,13 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import eu.xenit.apix.data.NodeRef; -import io.swagger.annotations.ApiModelProperty; /** * Created by Michiel Huygen on 12/05/2016. */ class CheckoutBody { - @ApiModelProperty(required = true) public NodeRef original; - @ApiModelProperty("Optional, if not specified uses the original node's folder. " + - "If current user does not have permissions for this folder, the working copy is created in the user's home folder") public NodeRef destinationFolder; @JsonCreator diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java index 6af0e2ab..536b4d81 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java @@ -3,9 +3,6 @@ import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.node.INodeService; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; @@ -25,8 +22,6 @@ public WorkingcopiesWebscript1(INodeService nodeService) { } @PostMapping(value = "/v1/workingcopies") - @ApiOperation("Checks out a new working copy for given node") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = NoderefResult.class)) public ResponseEntity createWorkingcopy(@RequestBody CheckoutBody checkoutBody) { final NodeRef originalRef = checkoutBody.getOriginal(); NodeRef destinationRef = checkoutBody.getDestinationFolder(); @@ -43,13 +38,7 @@ public ResponseEntity createWorkingcopy(@RequestBody CheckoutBody checkoutBod return respondDoesNotExist(destinationRef); } - @ApiOperation(value = "Checks in given working copy and removes it", - notes = "Returns the noderef of the original node") @PostMapping(value = "/v1/workingcopies/{space}/{store}/{guid}/checkin") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success", response = NoderefResult.class), - @ApiResponse(code = 404, message = "Not found") - }) public ResponseEntity checkinWorkingcopy(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid, @RequestBody final CheckinBody checkinBody) { @@ -61,12 +50,7 @@ public ResponseEntity checkinWorkingcopy(@PathVariable final String space, @P return respondDoesNotExist(nodeRef); } - @ApiOperation(value = "Cancels and removes a working copy", notes = "Returns the noderef of the original node") @DeleteMapping(value = "/v1/workingcopies/{space}/{store}/{guid}") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success", response = NoderefResult.class), - @ApiResponse(code = 404, message = "Not found") - }) public ResponseEntity cancelWorkingcopy(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid) { final NodeRef workingCopyRef = createNodeRef(space, store, guid); @@ -77,12 +61,7 @@ public ResponseEntity cancelWorkingcopy(@PathVariable final String space, @Pa return respondDoesNotExist(workingCopyRef); } - @ApiOperation("Returns the original node for given working copy") @GetMapping(value = "/v1/workingcopies/{space}/{store}/{guid}/original") - @ApiResponses({ - @ApiResponse(code = 200, message = "Success", response = NoderefResult.class), - @ApiResponse(code = 404, message = "Not Found") - }) public ResponseEntity getWorkingCopySource(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid) { NodeRef workingCopyRef = createNodeRef(space, store, guid); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java index c923bb95..d30b0cd8 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java @@ -6,9 +6,6 @@ import eu.xenit.apix.people.IPeopleService; import eu.xenit.apix.people.Person; import eu.xenit.apix.rest.v2.ApixV2Webscript; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -36,15 +33,11 @@ public GroupsWebscript(IPeopleService personService) { } @GetMapping(value = "/v2/groups") - @ApiOperation(value = "Returns a list containing all groups") - @ApiResponses(@ApiResponse(code = HttpStatus.SC_OK, message = "Success", response = Group[].class)) public ResponseEntity> GetAllGroups() { return writeJsonResponse(personService.GetGroups()); } @GetMapping(value = "/v2/groups/{name}/people") - @ApiOperation(value = "Returns the persons within a specific group") - @ApiResponses(@ApiResponse(code = HttpStatus.SC_OK, message = "Success", response = Person[].class)) public ResponseEntity GetPeopleOfGroup(@PathVariable final String name, @RequestParam(required = false) Boolean immediate) { if (immediate == null) { @@ -58,8 +51,6 @@ public ResponseEntity GetPeopleOfGroup(@PathVariable final String name, } @GetMapping(value = "/v2/groups/{name}/groups") - @ApiOperation(value = "Returns the groups within a specific group") - @ApiResponses(@ApiResponse(code = HttpStatus.SC_OK, message = "Success", response = Group[].class)) public ResponseEntity GetGroupsOfGroup(@PathVariable final String name, @RequestParam(required = false) Boolean immediate) { if (immediate == null) { @@ -74,8 +65,6 @@ public ResponseEntity GetGroupsOfGroup(@PathVariable final String name, } @PutMapping(value = "/v2/groups/{name}/people") - @ApiOperation(value = "Sets the complete list of people as direct members of this group") - @ApiResponses(@ApiResponse(code = HttpStatus.SC_OK, message = "Success", response = Group[].class)) public ResponseEntity SetPeopleInGroup(@PathVariable final String name, @RequestBody SetUsersInGroupOptions options) { // We want to replace all of the users in group {name} by a new list of users @@ -101,8 +90,6 @@ public ResponseEntity SetPeopleInGroup(@PathVariable final String name, @PutMapping(value = "/v2/groups/{name}/groups") - @ApiOperation(value = "Sets the complete list of direct subgroups for this group") - @ApiResponses(@ApiResponse(code = HttpStatus.SC_OK, message = "Success", response = Group[].class)) public ResponseEntity SetGroupsOfGroup(@PathVariable final String name, @RequestBody SetSubgroupOptions options) { // We want to replace all of the subgroups of {name} by a new list of subgroups diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetSubgroupOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetSubgroupOptions.java index bb2a2af6..d449283e 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetSubgroupOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetSubgroupOptions.java @@ -2,11 +2,9 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModelProperty; class SetSubgroupOptions { - @ApiModelProperty(required = true) private String[] subgroups; @JsonCreator diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetUsersInGroupOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetUsersInGroupOptions.java index 1f7c700a..7aff12a5 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetUsersInGroupOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetUsersInGroupOptions.java @@ -2,11 +2,9 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModelProperty; class SetUsersInGroupOptions { - @ApiModelProperty(required = true) private String[] users; @JsonCreator diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java index ad1171c8..64be5f31 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java @@ -11,9 +11,6 @@ import eu.xenit.apix.rest.v1.nodes.CreateNodeOptions; import eu.xenit.apix.rest.v1.nodes.NodeInfo; import eu.xenit.apix.rest.v2.ApixV2Webscript; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -54,11 +51,7 @@ public NodesWebscriptV2(INodeService nodeService, IPermissionService permissionS this.serviceRegistry = serviceRegistry; } - @ApiOperation("Returns combined information of a node." + - "\nNote: versionstore does not support sourceAssocs. " + - "For version nodes, an empty list added to the result") @GetMapping(value = "/v2/nodes/{space}/{store}/{guid}") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = NodeInfo.class)) public ResponseEntity getAllInfo(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -70,44 +63,7 @@ public ResponseEntity getAllInfo(@PathVariable String space, return writeJsonResponse(nodeInfo); } - @ApiOperation(value = "Returns combined information of multiple nodes", - notes = "Example to get combined information of multiple nodes:\n" + - "\n" + - "```\n" + - "POST /apix/v1/nodes/nodeInfo\n" + - "{\n" + - "\"retrieveMetadata\" : true, \n" + - "\"retrievePath\" : true, \n" + - "\"retrievePermissions\" : true, \n" + - "\"retrieveAssocs\" : true, \n" + - "\"retrieveChildAssocs\" : true, \n" + - "\"retrieveParentAssocs\" : true, \n" + - "\"retrieveTargetAssocs\" : true, \n" + - "\"noderefs\": [ \n" + - " \"workspace://SpacesStore/123456789\", \n" + - " \"workspace://SpacesStore/147258369\", \n" + - " \"workspace://SpacesStore/478159236\" \n" + - "]}\n" + - "```" + - "\n" + - "'retrieveMetadata', 'retrievePath', 'retrievePermissions', 'retrieveAssocs', " + - "'retrieveChildAssocs',\n" - + - "'retrieveParentAssocs', 'retrieveTargetAssocs' are optional parameters.\n" + - "Set 'retrieveMetadata' to false to omit the aspects and properties from the result.\n" + - "Set 'retrievePath' to false to omit the path from the result.\n" + - "Set 'retrievePermissions' to false to omit the permissions from the result.\n" + - "Set 'retrieveAssocs' to false to omit the associations (parent associations, child associations," + - " peer associations) from the result.\n" - + - "Set 'retrieveChildAssocs' to false to omit the child associations from the result.\n" + - "Set 'retrieveParentAssocs' to false to omit the parent associations from the result.\n" + - "Set 'retrieveTargetAssocs' to false to omit the peer target associations from the result.\n" + - "Set 'retrieveSourceAssocs' to false to omit the peer source associations from the result. " + - "Note: versionstore does not support sourceAssocs. For version nodes, an empty list added to the " + - "result\n") @PostMapping(value = "/v2/nodes/nodeInfo") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = NodeInfo[].class)) // TODO FIXME @Zlatin Alfresco MVC POJO MUCH? WTF. public ResponseEntity getAllInfos(@RequestBody final String requestString) throws JSONException { logger.debug("entered getAllInfo method"); @@ -200,13 +156,7 @@ public ResponseEntity getAllInfos(@RequestBody final String requestString) th return writeJsonResponse(nodeInfoList); } - @ApiOperation(value = "Retrieve current user's permissions for a node", - notes = "Returns a key-value map of permissions keys to a value of 'DENY' or 'ALLOW'. " + - "Possible keys are: Read, Write, Delete, CreateChildren, ReadPermissions, ChangePermissions, " + - "or custom permissions") @GetMapping(value = "/v2/nodes/{space}/{store}/{guid}/permissions") - @ApiResponses( - @ApiResponse(code = 200, message = "Success", response = PermissionValue.class, responseContainer = "Map")) public ResponseEntity> getPermissions(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -216,9 +166,7 @@ public ResponseEntity> getPermissions(@PathVariable ); } - @ApiOperation("Creates or copies a node") @PostMapping(value = "/v2/nodes") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = NodeInfo.class)) public ResponseEntity createNode(@RequestBody final CreateNodeOptions createNodeOptions) { final StringBuilder errorMessage = new StringBuilder(); final AtomicInteger errorCode = new AtomicInteger(); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java index 78aea183..a62b9df5 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java @@ -5,9 +5,6 @@ import eu.xenit.apix.people.IPeopleService; import eu.xenit.apix.people.Person; import eu.xenit.apix.rest.v2.ApixV2Webscript; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; @@ -31,8 +28,6 @@ public PeopleWebscript(IPeopleService personService) { } @GetMapping(value = "/v2/people/id/{space}/{store}/{guid}") - @ApiOperation(value = "Returns person information") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Person.class)) public ResponseEntity getPerson(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid) { @@ -51,22 +46,16 @@ public ResponseEntity getPerson(@PathVariable final String space, } @GetMapping(value = "/v2/people") - @ApiOperation(value = "Returns all people") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Person[].class)) public ResponseEntity> getAllPeople() { return writeJsonResponse(personService.GetPeople()); } @GetMapping(value = "/v2/people/-me-") - @ApiOperation(value = "Returns current user information") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Person.class)) public ResponseEntity getPersonCurrentUser() { return getPersonWithName("-me-"); } @GetMapping(value = "/v2/people/{name}") - @ApiOperation(value = "Returns person information") - @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Person.class)) public ResponseEntity getPersonWithName(@PathVariable final String name) { logger.debug("Asked person with name: {}", name); try{ @@ -83,8 +72,6 @@ public ResponseEntity getPersonWithName(@PathVariable final String name) { } @GetMapping(value = "/v2/ people/containergroups/{name}") - @ApiOperation(value = "Returns container groups of person") - @ApiResponses(value = @ApiResponse(code = 200, message = "Success", response = String[].class)) public ResponseEntity> getContainerGroupsOf(@PathVariable final String name) { logger.debug("Asked containergroups for person with name: {}", name); Set result = personService.GetContainerGroups(name); diff --git a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/DocumentationWebscriptTest.java b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/DocumentationWebscriptTest.java deleted file mode 100644 index cf075418..00000000 --- a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/DocumentationWebscriptTest.java +++ /dev/null @@ -1,67 +0,0 @@ -//package eu.xenit.apix.rest; -// -//import static org.mockito.Mockito.eq; -//import static org.mockito.Mockito.mock; -//import static org.mockito.Mockito.verify; -//import static org.mockito.Mockito.when; -// -//import com.fasterxml.jackson.core.JsonProcessingException; -//import eu.xenit.apix.rest.v1.DocumentationWebscript; -//import eu.xenit.apix.version.IVersionService; -//import eu.xenit.apix.version.VersionDescription; -//import eu.xenit.apix.web.IWebUtils; -//import io.swagger.models.Path; -//import io.swagger.models.Swagger; -//import io.swagger.models.properties.MapProperty; -//import io.swagger.models.properties.Property; -//import io.swagger.util.Json; -//import org.junit.Assert; -//import org.junit.Test; -//import org.springframework.extensions.surf.util.URLEncoder; -//import org.springframework.extensions.webscripts.WebScriptRequest; -//import org.springframework.extensions.webscripts.WebScriptResponse; -// -// -//public class DocumentationWebscriptTest { -// -// @Test -// public void TestGenerate() throws JsonProcessingException { -// String swagText = Json.mapper().writeValueAsString(generateSwagger()); -// System.out.println(swagText); -// Assert.assertTrue(0 < swagText.length()); -// } -// -// @Test -// public void TestPermissionsMap() { -// Swagger swag = generateSwagger(); -// Path path = swag.getPath("/v1/nodes/{space}/{store}/{guid}/permissions"); -// Property schema = path.getGet().getResponses().get("200").getSchema(); -// Assert.assertTrue("Nodes permissions get should return a map", schema instanceof MapProperty); -// System.out.println(schema); -// } -// -// private Swagger generateSwagger() { -// IVersionService version = mock(IVersionService.class); -// IWebUtils webUtils = mock(IWebUtils.class); -// when(version.getVersionDescription()).thenReturn(new VersionDescription("1.0.unittest", "description")); -// when(webUtils.getHost()).thenReturn("http"); -// DocumentationWebscript web = new DocumentationWebscript(version, webUtils); -// return web.generateSwagger(); -// } -// -// @Test -// public void testRedirectToSwaggerUi() { -// WebScriptRequest request = mock(WebScriptRequest.class); -// String serviceContextPath = "https://testdomain.com/alfresco/service"; -// when(request.getServiceContextPath()).thenReturn(serviceContextPath); -// when(request.getServicePath()).thenReturn(serviceContextPath.concat("/apix/v1/docs/ui")); -// WebScriptResponse response = mock(WebScriptResponse.class); -// DocumentationWebscript documentationWebscript = new DocumentationWebscript(mock(IVersionService.class), -// mock(IWebUtils.class)); -// documentationWebscript.redirectToSwaggerUi(request, response); -// verify(response).setStatus(302); -// verify(response).setHeader(eq("Location"), -// eq("https://testdomain.com/alfresco/service/swagger/ui/?url=" + URLEncoder -// .encode("https://testdomain.com/alfresco/service/apix/v1/docs/swagger.json"))); -// } -//} diff --git a/build.gradle b/build.gradle index 9ad6bb9d..cc5e7e48 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,6 @@ ext { de_version = "3.0.0" mvc = "8.0.0" jackson_version = '2.8.3' - swagger_version = "1.5.7" // 2.2.4 care4alfVersion = '2.3.0' http_version = "4.3.4" // Used by integration tests } From ed4861f0b9986fae7c3fa0037d3bffd38b5e6c5a Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski <6491638+todorinskiz@users.noreply.github.com> Date: Wed, 1 Feb 2023 20:54:41 +0200 Subject: [PATCH 27/90] ALFREDAPI-504 Removed obsolete file; Fixed some TODOs and removed some to be reviewed in documentation --- .../apix/alfresco/metadata/NodeService.java | 1 - .../java/eu/xenit/apix/node/NodeMetadata.java | 4 -- .../staging/workflow/WorkflowWebscript.java | 2 - .../apix/rest/v1/nodes/NodesWebscript1.java | 13 +++-- .../v1/properties/PropertiesWebScript1.java | 1 - .../apix/rest/v2/nodes/NodesWebscriptV2.java | 1 - .../module/alfred-api/module.properties | 52 ------------------- 7 files changed, 10 insertions(+), 64 deletions(-) delete mode 100644 apix-rest-v1/src/main/resources/alfresco/module/alfred-api/module.properties diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/metadata/NodeService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/metadata/NodeService.java index e911b3ca..3dd204c5 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/metadata/NodeService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/metadata/NodeService.java @@ -671,7 +671,6 @@ public void setContent(eu.xenit.apix.data.NodeRef node, eu.xenit.apix.data.Conte @Override - // TODO @Zlatin MVC Extract file name in ContentInputStream pojo public eu.xenit.apix.data.ContentInputStream getContent(eu.xenit.apix.data.NodeRef nodeRef) { final ContentReader reader; try { diff --git a/apix-interface/src/main/java/eu/xenit/apix/node/NodeMetadata.java b/apix-interface/src/main/java/eu/xenit/apix/node/NodeMetadata.java index f1f18a1f..e11897da 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/node/NodeMetadata.java +++ b/apix-interface/src/main/java/eu/xenit/apix/node/NodeMetadata.java @@ -22,10 +22,6 @@ public class NodeMetadata { public List aspects; //TODO: parent - //Removed in favor of using the permissions endpoint public boolean canEditMetadata; // TODO: remove - - //public NodeAssociation[] associations; - public NodeMetadata(NodeRef id, QName type, QName baseType, long transactionId, Map> properties, List aspects) { this.id = id; diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java index 90610dbe..f4ef63dc 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java @@ -110,8 +110,6 @@ public ResponseEntity updateTask(@PathVariable final String id, return responseFrom(workflowService.updateTask(id, changes)); } catch (Error ex) { return ResponseEntity.status(HttpStatus.SC_CONFLICT).build(); - // TODO @Zlatin Alfresco MVC -// responseFrom(webScriptResponse, ex); } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java index 55696fce..17bc59f0 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java @@ -41,7 +41,16 @@ import org.slf4j.LoggerFactory; import org.springframework.core.io.InputStreamResource; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @@ -290,7 +299,6 @@ public ResponseEntity getAllInfoOfNode(@PathVariable String space, @Path } @PostMapping(value = "/v1/nodes/nodeInfo") - // TODO @Zlatin MVC Pojo public ResponseEntity getAllInfoOfNodes(@RequestBody final String requestString) { logger.debug("request content: {}", requestString); JSONObject jsonObject = new JSONObject(requestString); @@ -584,7 +592,6 @@ public ResponseEntity exists(@PathVariable String space, @PathVariable @PostMapping(value = "/v1/nodes/upload") - // TODO @Zlatin MVC Pojo public ResponseEntity uploadNode( @RequestPart(required = false) String type, @RequestPart(required = false) String parent, diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java index 3c1944d3..228ee19e 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java @@ -31,7 +31,6 @@ public PropertiesWebScript1(IPropertyService propertyService) { //https://stackoverflow.com/questions/13482020/encoded-slash-2f-with-spring-requestmapping-path-param-gives-http-400 public ResponseEntity getPropertyDefinition(@PathVariable final QName qname, @RequestParam(required = false) QName qnameWithSlash) { - // TODO @Zlatin FIXME Alfresco MVC some crappy URL shenanigans ? Unit-tested? QName apixQName = qnameWithSlash != null ? qnameWithSlash : qname; PropertyDefinition propDef = propertyService.GetPropertyDefinition(apixQName); if (propDef == null) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java index 64be5f31..eec117b7 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java @@ -64,7 +64,6 @@ public ResponseEntity getAllInfo(@PathVariable String space, } @PostMapping(value = "/v2/nodes/nodeInfo") - // TODO FIXME @Zlatin Alfresco MVC POJO MUCH? WTF. public ResponseEntity getAllInfos(@RequestBody final String requestString) throws JSONException { logger.debug("entered getAllInfo method"); if (requestString == null || requestString.isEmpty()) { diff --git a/apix-rest-v1/src/main/resources/alfresco/module/alfred-api/module.properties b/apix-rest-v1/src/main/resources/alfresco/module/alfred-api/module.properties deleted file mode 100644 index b61f87a8..00000000 --- a/apix-rest-v1/src/main/resources/alfresco/module/alfred-api/module.properties +++ /dev/null @@ -1,52 +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. - - - -# SDK Sample module - -# ==== Beginning of Alfresco required/optional properties ====== # -# NB: These properties are filtered at build time by Maven, single -# sourcing from POM properties -#module.id=${project.name} -module.id=alfred-api -#module.aliases=myModule-123, my-module -#module.title=${project.name} -module.title=Alfred API -#module.description=${project.description} -module.description=Alfred API: Java and ReST APIs -#module.version=${project.version} -module.version=4.0 - -# The following optional properties can be used to prevent the module from being added -# to inappropriate versions of the WAR file. -# module.repo.version.min=2.0 -# module.repo.version.max=2.1 - -# FIXME: This dependencies should come out of mvn dependencies on amp - -# The following describe dependencies on other modules -# Depends on net.sf.myproject.module.SupportModuleA version ${version} or later -# module.depends.net.sf.myproject.module.SupportModuleA=${version}-* -# Depends on net.sf.myproject.module.SupportModuleA version ${version} to 2.0 -# module.depends.net.sf.myproject.module.SupportModuleB=${version}-2.0 -# Depends on net.sf.myproject.module.SupportModuleC - any version -# module.depends.net.sf.myproject.module.SupportModuleB=* - - -# ==== End of Alfresco required/optional properties ======= # - - -# ==== Beginning of module required properties/optional ====== # \ No newline at end of file From c7cb31da318126a7d30d8de3f99fa37ac210b625 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski <6491638+todorinskiz@users.noreply.github.com> Date: Wed, 1 Feb 2023 21:01:18 +0200 Subject: [PATCH 28/90] ALFREDAPI-504 Add missing gitkeep file for 7.3 version --- apix-impl/73/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apix-impl/73/.gitkeep diff --git a/apix-impl/73/.gitkeep b/apix-impl/73/.gitkeep new file mode 100644 index 00000000..e69de29b From 65fe0764f45ba53db97f71d53aded39e976e7810 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski <6491638+todorinskiz@users.noreply.github.com> Date: Wed, 1 Feb 2023 21:31:49 +0200 Subject: [PATCH 29/90] ALFREDAPI-504 Reverted unintended changes; Added PR feedback on Groovy string interpolation --- apix-docker/70/docker-compose.yml | 18 +++++++++--------- apix-docker/71/docker-compose.yml | 18 +++++++++--------- apix-docker/72/docker-compose.yml | 20 ++++++++++---------- apix-docker/build.gradle | 4 ++-- apix-impl/build.gradle | 12 ++++++------ apix-integrationtests/alfresco/build.gradle | 12 ++++++------ apix-rest-v1/build.gradle | 8 ++++---- 7 files changed, 46 insertions(+), 46 deletions(-) diff --git a/apix-docker/70/docker-compose.yml b/apix-docker/70/docker-compose.yml index 9d9b6341..1e4b188c 100644 --- a/apix-docker/70/docker-compose.yml +++ b/apix-docker/70/docker-compose.yml @@ -31,15 +31,15 @@ services: - POSTGRES_DB=alfresco restart: unless-stopped -# activemq: -# image: alfresco/alfresco-activemq:5.16.1 -# mem_limit: 1g -# -# transform-core-aio: -# image: alfresco/alfresco-transform-core-aio:2.5.0 -# environment: -# JAVA_OPTS: " -Xms256m -Xmx512m" -# ACTIVEMQ_URL: "nio://activemq:61616" + activemq: + image: alfresco/alfresco-activemq:5.16.1 + mem_limit: 1g + + transform-core-aio: + image: alfresco/alfresco-transform-core-aio:2.5.0 + environment: + JAVA_OPTS: " -Xms256m -Xmx512m" + ACTIVEMQ_URL: "nio://activemq:61616" volumes: alfresco: diff --git a/apix-docker/71/docker-compose.yml b/apix-docker/71/docker-compose.yml index 9d9b6341..1e4b188c 100644 --- a/apix-docker/71/docker-compose.yml +++ b/apix-docker/71/docker-compose.yml @@ -31,15 +31,15 @@ services: - POSTGRES_DB=alfresco restart: unless-stopped -# activemq: -# image: alfresco/alfresco-activemq:5.16.1 -# mem_limit: 1g -# -# transform-core-aio: -# image: alfresco/alfresco-transform-core-aio:2.5.0 -# environment: -# JAVA_OPTS: " -Xms256m -Xmx512m" -# ACTIVEMQ_URL: "nio://activemq:61616" + activemq: + image: alfresco/alfresco-activemq:5.16.1 + mem_limit: 1g + + transform-core-aio: + image: alfresco/alfresco-transform-core-aio:2.5.0 + environment: + JAVA_OPTS: " -Xms256m -Xmx512m" + ACTIVEMQ_URL: "nio://activemq:61616" volumes: alfresco: diff --git a/apix-docker/72/docker-compose.yml b/apix-docker/72/docker-compose.yml index fa275fde..1e4b188c 100644 --- a/apix-docker/72/docker-compose.yml +++ b/apix-docker/72/docker-compose.yml @@ -4,7 +4,7 @@ services: alfresco-core: image: ${DOCKER_IMAGE} ports: - - "${DOCKER_IP}:8080:8080" + - "${DOCKER_IP}::8080" volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped @@ -31,15 +31,15 @@ services: - POSTGRES_DB=alfresco restart: unless-stopped -# activemq: -# image: alfresco/alfresco-activemq:5.16.1 -# mem_limit: 1g -# -# transform-core-aio: -# image: alfresco/alfresco-transform-core-aio:2.5.0 -# environment: -# JAVA_OPTS: " -Xms256m -Xmx512m" -# ACTIVEMQ_URL: "nio://activemq:61616" + activemq: + image: alfresco/alfresco-activemq:5.16.1 + mem_limit: 1g + + transform-core-aio: + image: alfresco/alfresco-transform-core-aio:2.5.0 + environment: + JAVA_OPTS: " -Xms256m -Xmx512m" + ACTIVEMQ_URL: "nio://activemq:61616" volumes: alfresco: diff --git a/apix-docker/build.gradle b/apix-docker/build.gradle index f2b49257..e42f4383 100644 --- a/apix-docker/build.gradle +++ b/apix-docker/build.gradle @@ -15,8 +15,8 @@ subprojects { alfrescoAmp project(path: ":apix-impl:apix-impl-${subproject_alfresco_version}", configuration: 'ampArtifact') alfrescoAmp project(path: ':apix-integrationtests:model-amp', configuration: 'ampArchives') alfrescoAmp project(path: ':apix-rest-v1', configuration: 'ampArtifact') - alfrescoSM "com.gradecak.alfresco-mvc:alfresco-mvc-rest:$mvc" - alfrescoSM "com.gradecak.alfresco-mvc:alfresco-mvc-aop:$mvc" + alfrescoSM "com.gradecak.alfresco-mvc:alfresco-mvc-rest:${mvc}" + alfrescoSM "com.gradecak.alfresco-mvc:alfresco-mvc-aop:${mvc}" alfrescoSM files(jar) alfrescoAmp "eu.xenit:alfresco-dynamic-extensions-repo-${subproject_alfresco_version}:${de_version}@amp" } diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index ac04b283..96909633 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -1,7 +1,7 @@ sourceSets.main.java.srcDirs += 'src/main/java' subprojects { def shortAlfrescoVersion = project.name.split("-")[2] - apply from: "${rootProject.projectDir}/alfresco/$shortAlfrescoVersion/overrides.gradle" + apply from: "${rootProject.projectDir}/alfresco/${shortAlfrescoVersion}/overrides.gradle" apply from: "${rootProject.projectDir}/publish.gradle" apply plugin: 'eu.xenit.amp' apply plugin: 'java-library' @@ -30,7 +30,7 @@ subprojects { sourceSets { main { java { - srcDirs = ["$project.parent.projectDir/src/main/java"] + srcDirs = ["${project.parent.projectDir}/src/main/java"] } amp { module { @@ -50,7 +50,7 @@ subprojects { } test { java { - srcDirs = ["$project.parent.projectDir/src/test/java"] + srcDirs = ["${project.parent.projectDir}/src/test/java"] } testResultsDirName = "${project.parent.buildDir}/test-results/test" } @@ -80,7 +80,7 @@ allprojects { // Subproject of supported Alfresco version 61/62/70/71/72 def subproject_alfresco_version = project.projectDir.name == "apix-impl" ? "70" : project.projectDir.name - apply from: "$rootProject.projectDir/alfresco/$subproject_alfresco_version/overrides.gradle" + apply from: "$rootProject.projectDir/alfresco/${subproject_alfresco_version}/overrides.gradle" // allprojects also applies to shared code (under apix-impl/src) that needs to work in IntelliJ apply plugin: 'eu.xenit.alfresco' apply plugin: 'java-library' @@ -89,14 +89,14 @@ allprojects { api(project(":apix-interface")) implementation 'commons-lang:commons-lang:1.0' - alfrescoProvided platform("org.alfresco:acs-community-packaging:$alfresco_version") + alfrescoProvided platform("org.alfresco:acs-community-packaging:${alfresco_version}") alfrescoProvided("org.alfresco:alfresco-repository") alfrescoProvided('org.alfresco:alfresco-remote-api') implementation group: 'org.yaml', name: 'snakeyaml', version: '1.15' implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final' - testImplementation platform("org.alfresco:acs-community-packaging:$alfresco_version") + testImplementation platform("org.alfresco:acs-community-packaging:${alfresco_version}") testImplementation 'org.alfresco:alfresco-repository' testImplementation 'org.alfresco:alfresco-remote-api' testImplementation 'org.alfresco:alfresco-data-model' diff --git a/apix-integrationtests/alfresco/build.gradle b/apix-integrationtests/alfresco/build.gradle index 3a1cd818..8b8788ed 100644 --- a/apix-integrationtests/alfresco/build.gradle +++ b/apix-integrationtests/alfresco/build.gradle @@ -11,13 +11,13 @@ allprojects { apply plugin: 'eu.xenit.de' apply plugin: 'eu.xenit.alfresco-remote-testrunner' apply plugin: 'eu.xenit.alfresco' - apply from: "$rootProject.projectDir/alfresco/$subproject_alfresco_version/overrides.gradle" + apply from: "${rootProject.projectDir}/alfresco/${subproject_alfresco_version}/overrides.gradle" sourceSets { main.java.srcDirs = [] main.resources.srcDirs = [] - integrationTest.java.srcDirs = ["$integrationTestsProjectDir/src/main/java"] - integrationTest.resources.srcDirs = ["$integrationTestsProjectDir/src/main/resources"] + integrationTest.java.srcDirs = ["${integrationTestsProjectDir}/src/main/java"] + integrationTest.resources.srcDirs = ["${integrationTestsProjectDir}/src/main/resources"] } configurations { @@ -40,14 +40,14 @@ allprojects { alfrescoProvided(project(":apix-interface")) { transitive = false } // Add services used to the integration test fatjar, since we can't access the ones deployed in Alfresco - integrationTestImplementationRemote(project(":apix-impl:apix-impl-$subproject_alfresco_version")) { + integrationTestImplementationRemote (project(":apix-impl:apix-impl-${subproject_alfresco_version}")) { // Already includes apix-interface, we need to exclude it to avoid Linkage errors from // having 2 of the same classes on the classpath // (1 in Alfresco from apix-impl AMP + 1 in DE from the integration tests fat jar) exclude(group: "eu.xenit.apix", module: "apix-interface") } - integrationTestImplementationRemote("org.apache.httpcomponents:fluent-hc:$http_version") { + integrationTestImplementationRemote("org.apache.httpcomponents:fluent-hc:${http_version}") { exclude group: 'commons-logging' exclude group: 'org.apache.httpcomponents', module: 'httpcore' } @@ -61,7 +61,7 @@ allprojects { // The proper way is a fix of alfresco-remote-testrunner, but until then we use this workaround. integrationTestImplementationLocal "commons-lang:commons-lang:1.0" - alfrescoProvided platform("org.alfresco:acs-community-packaging:$alfresco_version") + alfrescoProvided platform("org.alfresco:acs-community-packaging:${alfresco_version}") alfrescoProvided("org.alfresco:alfresco-repository") alfrescoProvided('org.alfresco:alfresco-remote-api') alfrescoProvided('org.alfresco:alfresco-data-model') diff --git a/apix-rest-v1/build.gradle b/apix-rest-v1/build.gradle index d50a4a4a..f94ddbf2 100644 --- a/apix-rest-v1/build.gradle +++ b/apix-rest-v1/build.gradle @@ -18,20 +18,20 @@ artifacts { apply from: "$rootProject.projectDir/alfresco/70/overrides.gradle" dependencies { - implementation platform("org.alfresco:acs-community-packaging:$alfresco_version") + implementation platform("org.alfresco:acs-community-packaging:${alfresco_version}") // Alfresco dependency should be removed in the future alfrescoProvided("org.alfresco:alfresco-repository") alfrescoProvided project(':apix-interface') alfrescoProvided('org.alfresco:alfresco-remote-api') - alfrescoProvided "com.gradecak.alfresco-mvc:alfresco-mvc-rest:$mvc" - alfrescoProvided "com.gradecak.alfresco-mvc:alfresco-mvc-aop:$mvc" + alfrescoProvided "com.gradecak.alfresco-mvc:alfresco-mvc-rest:${mvc}" + alfrescoProvided "com.gradecak.alfresco-mvc:alfresco-mvc-aop:${mvc}" alfrescoProvided "javax.servlet:javax.servlet-api:4.0.1" testImplementation project(':apix-interface') testImplementation project(':apix-impl') - testImplementation platform("org.alfresco:acs-community-packaging:$alfresco_version") + testImplementation platform("org.alfresco:acs-community-packaging:${alfresco_version}") testImplementation 'org.springframework:spring-core' testImplementation 'org.springframework:spring-test' testImplementation "org.alfresco.surf:spring-webscripts" From 65cad64cb9ee61be7a2df0b77ac9664c126a76a7 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski <6491638+todorinskiz@users.noreply.github.com> Date: Thu, 2 Feb 2023 10:05:07 +0200 Subject: [PATCH 30/90] ALFREDAPI-504 Fixed broken mockito dependencies --- .../xenit/apix/tests/search/SearchFacetServiceUnitTest.java | 4 ++-- .../eu/xenit/apix/tests/search/SearchServiceUnitTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apix-impl/src/test/java/eu/xenit/apix/tests/search/SearchFacetServiceUnitTest.java b/apix-impl/src/test/java/eu/xenit/apix/tests/search/SearchFacetServiceUnitTest.java index 6b0e381c..1a5f9670 100644 --- a/apix-impl/src/test/java/eu/xenit/apix/tests/search/SearchFacetServiceUnitTest.java +++ b/apix-impl/src/test/java/eu/xenit/apix/tests/search/SearchFacetServiceUnitTest.java @@ -1,8 +1,8 @@ package eu.xenit.apix.tests.search; import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/apix-impl/src/test/java/eu/xenit/apix/tests/search/SearchServiceUnitTest.java b/apix-impl/src/test/java/eu/xenit/apix/tests/search/SearchServiceUnitTest.java index 106b5ec4..3c0dfc91 100644 --- a/apix-impl/src/test/java/eu/xenit/apix/tests/search/SearchServiceUnitTest.java +++ b/apix-impl/src/test/java/eu/xenit/apix/tests/search/SearchServiceUnitTest.java @@ -1,6 +1,6 @@ package eu.xenit.apix.tests.search; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; From 189ab1101eff4f4f90c96cbfd92211a4a90b0318 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski <6491638+todorinskiz@users.noreply.github.com> Date: Thu, 2 Feb 2023 11:58:20 +0200 Subject: [PATCH 31/90] ALFREDAPI-504 Updated maven group ID --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cc5e7e48..4db451b0 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ ext { subprojects { apply plugin: 'java' - group = 'eu.xenit.apix' + group = 'eu.xenit.alfred.api' version = versionWithoutQualifier + getVersionQualifier(System.env.BRANCH_NAME ?: 'local') sourceCompatibility = 11 targetCompatibility = 11 From da756e2af69b6c652f8c7da6bd3490360f4bb4e0 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski <6491638+todorinskiz@users.noreply.github.com> Date: Thu, 2 Feb 2023 12:06:07 +0200 Subject: [PATCH 32/90] ALFREDAPI-504 Updated changelog --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55b92653..98617548 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,10 @@ # Alfred API - Changelog -## 4.0.0 (yyyy-mm-dd) +## 4.0.1 (yyyy-mm-dd) ### Added ### Changed -* [ALFREDAPI-504](https://xenitsupport.jira.com/browse/ALFREDAPI-504): Refactored Alfred API from Dynamic Extensions to Alfresco MVC to reduce maintenance efforts and improve the integration with Spring ### Fixed @@ -23,6 +22,8 @@ ## 4.0.0 (2023-01-17) +Alfred API drops Dynamic Extensions in favor of Alfresco MVC to reduce maintenance efforts. +Updated maven group ID from "eu.xenit.apix" to "eu.xenit.alfred.api". This release adds support for Alfresco 7.3 and drops support for Alfresco 5.2 and 6.1. ### Added @@ -33,6 +34,7 @@ This release adds support for Alfresco 7.3 and drops support for Alfresco 5.2 an ### Removed * [ALFREDAPI-505](https://xenitsupport.jira.com/browse/ALFREDAPI-505): Drop support for Alfresco 5.2 and 6.1 +* [ALFREDAPI-504](https://xenitsupport.jira.com/browse/ALFREDAPI-504): Drop Dynamic Extensions in favor of Alfresco MVC ## 3.1.0 (2022-04-21) From 30e5abad675145878bb3ad4e92b3ac2807903425 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski <6491638+todorinskiz@users.noreply.github.com> Date: Thu, 2 Feb 2023 16:37:34 +0200 Subject: [PATCH 33/90] ALFREDAPI-504 Fix linkage errors --- apix-integrationtests/alfresco/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apix-integrationtests/alfresco/build.gradle b/apix-integrationtests/alfresco/build.gradle index 8b8788ed..0e6987c3 100644 --- a/apix-integrationtests/alfresco/build.gradle +++ b/apix-integrationtests/alfresco/build.gradle @@ -44,7 +44,7 @@ allprojects { // Already includes apix-interface, we need to exclude it to avoid Linkage errors from // having 2 of the same classes on the classpath // (1 in Alfresco from apix-impl AMP + 1 in DE from the integration tests fat jar) - exclude(group: "eu.xenit.apix", module: "apix-interface") + exclude(group: "eu.xenit.alfred.api", module: "apix-interface") } integrationTestImplementationRemote("org.apache.httpcomponents:fluent-hc:${http_version}") { From 3b0a4365adaaa9aba10568af4dde8cf44faf9be5 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Mon, 6 Feb 2023 11:57:30 +0100 Subject: [PATCH 34/90] ALFREDAPI-511: Fix GHA CI for MVC Gradle structure --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 429cdb72..63524149 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: arguments: >- --info :apix-impl:apix-impl-${{ matrix.alfresco_version }}:test - :apix-integrationtests:test-${{ matrix.alfresco_version }}:integrationTest + :apix-integrationtests:alfresco:${{ matrix.alfresco_version }}:integrationTest - name: Upload test reports if: always() uses: actions/upload-artifact@v3 From ec59474d3f03db73c32aef18bb4f32a1e72128dc Mon Sep 17 00:00:00 2001 From: Hechmi Dammak Date: Fri, 3 Mar 2023 10:22:20 +0100 Subject: [PATCH 35/90] XENOPS-1081 fix snapshot naming and bump version to 4.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4db451b0..8444293d 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ def static getVersionQualifier(String branch_name) { return '' // Osgi in 5x accepts - in qualifier, 6x does not. // Suggest removing branch section from snapshot qualifiers all together. - return '.SNAPSHOT' + return '-SNAPSHOT' } ext { From c617d9820d07938405e24704015223473f43e162 Mon Sep 17 00:00:00 2001 From: Jan Vanderloock Date: Fri, 24 Mar 2023 14:07:03 +0100 Subject: [PATCH 36/90] ALFREDAPI-516 Avoid multiple jackson versions on classpath --- apix-impl/build.gradle | 5 ++++- apix-interface/build.gradle | 5 ++--- apix-rest-v1/build.gradle | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index 96909633..c5ff1582 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -86,7 +86,10 @@ allprojects { apply plugin: 'java-library' dependencies { - api(project(":apix-interface")) + api(project(":apix-interface")) { + exclude group: 'com.fasterxml.jackson.core', module: 'jackson-annotations' + exclude group: 'com.fasterxml.jackson.core', module: 'jackson-databind' + } implementation 'commons-lang:commons-lang:1.0' alfrescoProvided platform("org.alfresco:acs-community-packaging:${alfresco_version}") diff --git a/apix-interface/build.gradle b/apix-interface/build.gradle index e406cda6..ae05a9a2 100644 --- a/apix-interface/build.gradle +++ b/apix-interface/build.gradle @@ -25,9 +25,8 @@ publishing { } dependencies { - implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jackson_version - implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: jackson_version - implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jackson_version + compileOnly "com.fasterxml.jackson.core:jackson-annotations:${jackson_version}" + compileOnly "com.fasterxml.jackson.core:jackson-databind:${jackson_version}" testImplementation group: 'junit', name: 'junit', version: '4.12' } diff --git a/apix-rest-v1/build.gradle b/apix-rest-v1/build.gradle index f94ddbf2..a211efd6 100644 --- a/apix-rest-v1/build.gradle +++ b/apix-rest-v1/build.gradle @@ -29,7 +29,7 @@ dependencies { alfrescoProvided "com.gradecak.alfresco-mvc:alfresco-mvc-aop:${mvc}" alfrescoProvided "javax.servlet:javax.servlet-api:4.0.1" - testImplementation project(':apix-interface') + testImplementation (project(':apix-interface')) {transitive = false} testImplementation project(':apix-impl') testImplementation platform("org.alfresco:acs-community-packaging:${alfresco_version}") testImplementation 'org.springframework:spring-core' From c2b8a719035ed4b09380563bdfee743d3bce0443 Mon Sep 17 00:00:00 2001 From: Jan Vanderloock Date: Fri, 24 Mar 2023 14:20:06 +0100 Subject: [PATCH 37/90] ALFREDAPI-516 Avoid multiple jackson versions on classpath --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98617548..7118de22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ ### Fixed ### Changed * [ALFREDAPI-509](https://xenitsupport.jira.com/browse/ALFREDAPI-509): Moved CI to Github Actions +* [ALFREDAPI-516](https://xenitsupport.jira.com/browse/ALFREDAPI-516): Classpath cleanup ### Removed From 0c3c5cc4d238b7443482378a22bbd12edacdffcf Mon Sep 17 00:00:00 2001 From: Hechmi Dammak Date: Mon, 3 Apr 2023 16:11:55 +0100 Subject: [PATCH 38/90] XENOPS-1081 fix bump version to 4.1.0 --- apix-docker/62/build.gradle | 2 +- apix-impl/build.gradle | 2 +- build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apix-docker/62/build.gradle b/apix-docker/62/build.gradle index bdc41d08..8324cebd 100644 --- a/apix-docker/62/build.gradle +++ b/apix-docker/62/build.gradle @@ -1,6 +1,6 @@ dependencies { baseAlfrescoWar platform("org.alfresco:acs-packaging:6.2.2.19") - baseAlfrescoWar 'org.alfresco:content-services:6.2.2.19@war' + baseAlfrescoWar 'org.alfresco:content-services@war' // Fix for https://github.com/xenit-eu/dynamic-extensions-for-alfresco#alfresco-61---wrong-version-of-commons-annotations-used alfrescoAmp(group: 'eu.xenit.alfresco', name: 'alfresco-hotfix-MNT-20557', version: '1.0.2', ext: 'amp') } diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index c5ff1582..acdbd89c 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -77,7 +77,7 @@ subprojects { } allprojects { - // Subproject of supported Alfresco version 61/62/70/71/72 + // Subproject of supported Alfresco version 62/70/71/72/73 def subproject_alfresco_version = project.projectDir.name == "apix-impl" ? "70" : project.projectDir.name apply from: "$rootProject.projectDir/alfresco/${subproject_alfresco_version}/overrides.gradle" diff --git a/build.gradle b/build.gradle index 8444293d..947c549d 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ def static getVersionQualifier(String branch_name) { } ext { - versionWithoutQualifier = '4.0.0' + versionWithoutQualifier = '4.1.0' de_version = "3.0.0" mvc = "8.0.0" jackson_version = '2.8.3' From 2223ec82c89a411465a4c6eeacbfed51e9580ae3 Mon Sep 17 00:00:00 2001 From: Zlatin Todorinski Date: Tue, 4 Apr 2023 09:18:43 +0200 Subject: [PATCH 39/90] ALFREDAPI-504 Package impl, interface and rest api in 1 amp to respect the interface abstraction --- .github/workflows/ci.yml | 2 +- alfresco/build.gradle | 69 +++++++++++++++++++ apix-docker/build.gradle | 3 +- apix-impl/build.gradle | 53 -------------- apix-rest-v1/build.gradle | 9 --- settings.gradle | 5 +- .../config/alfresco-global.properties | 0 {apix-impl => src}/config/log4j.properties | 0 .../config/messages/faceted-search.properties | 0 .../messages/faceted-search_de.properties | 0 .../messages/faceted-search_en.properties | 0 .../messages/faceted-search_es.properties | 0 .../messages/faceted-search_fr.properties | 0 .../messages/faceted-search_it.properties | 0 .../messages/faceted-search_ja.properties | 0 .../messages/faceted-search_nb.properties | 0 .../messages/faceted-search_nl.properties | 0 .../messages/faceted-search_pt_BR.properties | 0 .../messages/faceted-search_ru.properties | 0 .../messages/faceted-search_zh_CN.properties | 0 {apix-impl => src}/config/module-context.xml | 0 21 files changed, 75 insertions(+), 66 deletions(-) create mode 100644 alfresco/build.gradle rename {apix-impl => src}/config/alfresco-global.properties (100%) rename {apix-impl => src}/config/log4j.properties (100%) rename {apix-impl => src}/config/messages/faceted-search.properties (100%) rename {apix-impl => src}/config/messages/faceted-search_de.properties (100%) rename {apix-impl => src}/config/messages/faceted-search_en.properties (100%) rename {apix-impl => src}/config/messages/faceted-search_es.properties (100%) rename {apix-impl => src}/config/messages/faceted-search_fr.properties (100%) rename {apix-impl => src}/config/messages/faceted-search_it.properties (100%) rename {apix-impl => src}/config/messages/faceted-search_ja.properties (100%) rename {apix-impl => src}/config/messages/faceted-search_nb.properties (100%) rename {apix-impl => src}/config/messages/faceted-search_nl.properties (100%) rename {apix-impl => src}/config/messages/faceted-search_pt_BR.properties (100%) rename {apix-impl => src}/config/messages/faceted-search_ru.properties (100%) rename {apix-impl => src}/config/messages/faceted-search_zh_CN.properties (100%) rename {apix-impl => src}/config/module-context.xml (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 63524149..4411ffab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,4 +71,4 @@ jobs: arguments: >- --info -PsigningKeyId=DF8285F0 :apix-interface:publish - :apix-impl:apix-impl-${{ matrix.alfresco_version }}:publish + :alfresco:${{ matrix.alfresco_version }}:publish diff --git a/alfresco/build.gradle b/alfresco/build.gradle new file mode 100644 index 00000000..44ed8457 --- /dev/null +++ b/alfresco/build.gradle @@ -0,0 +1,69 @@ +subprojects { + apply from: "${project.projectDir}/overrides.gradle" + apply from: "${rootProject.projectDir}/publish.gradle" + apply plugin: 'eu.xenit.amp' + + configurations { + ampArtifact + } + + artifacts { + ampArtifact amp + } + + sourceSets { + main { + amp { + module { + it.put("module.id", "alfred-api-${project.name}") + it.put("module.title", "alfred-api-${project.name}") + it.put("module.description", + "Xenit Alfred API implementation Alfresco ${alfresco_version.substring(0, 3)}") + it.put("module.version", project.version) + it.put("module.repo.version.min", project.alfresco_min_version) + if(project.hasProperty("alfresco_max_version") + && project.alfresco_max_version != null) { + it.put("module.repo.version.max", project.alfresco_max_version) + } + } + } + } + } + + dependencies { + implementation(project(":apix-impl")) + implementation(project(":apix-impl:apix-impl-${project.name}")) + implementation(project(":apix-rest-v1")) + } + + publishing { + publications { + maven(MavenPublication) { + artifactId "alfred-api-${project.name}" + artifact tasks.amp + } + } + } + + project.tasks.jar.enabled = false + + // Extend amp plugin task: + // We want to add 'alfresco-global.properties' etc to the module-specific folder in the AMP + // (e.g. 'config/module/alfresco/module/apix-impl-61/') without hard-coding project name for each Alfresco version. + amp { + archiveBaseName = "alfred-api-${project.name}" + into("config/alfresco/module/${project.name}") { + from("${rootProject.projectDir}/src/config/alfresco-global.properties") + from("${rootProject.projectDir}/src/config/log4j.properties") + from("${rootProject.projectDir}/src/config/module-context.xml") + expand(moduleId: project.name) + } + into("config/alfresco/module/${project.name}/messages") { + from("${rootProject.projectDir}/src/config/messages/") + } + } + + afterEvaluate { + signMavenPublication.dependsOn amp + } +} diff --git a/apix-docker/build.gradle b/apix-docker/build.gradle index e42f4383..11b03727 100644 --- a/apix-docker/build.gradle +++ b/apix-docker/build.gradle @@ -12,9 +12,8 @@ subprojects { def subproject_alfresco_version = project.name.substring(project.name.length() - 2) dependencies { - alfrescoAmp project(path: ":apix-impl:apix-impl-${subproject_alfresco_version}", configuration: 'ampArtifact') + alfrescoAmp project(path: ":alfresco:${subproject_alfresco_version}", configuration: 'ampArtifact') alfrescoAmp project(path: ':apix-integrationtests:model-amp', configuration: 'ampArchives') - alfrescoAmp project(path: ':apix-rest-v1', configuration: 'ampArtifact') alfrescoSM "com.gradecak.alfresco-mvc:alfresco-mvc-rest:${mvc}" alfrescoSM "com.gradecak.alfresco-mvc:alfresco-mvc-aop:${mvc}" alfrescoSM files(jar) diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index c5ff1582..78997450 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -2,51 +2,17 @@ sourceSets.main.java.srcDirs += 'src/main/java' subprojects { def shortAlfrescoVersion = project.name.split("-")[2] apply from: "${rootProject.projectDir}/alfresco/${shortAlfrescoVersion}/overrides.gradle" - apply from: "${rootProject.projectDir}/publish.gradle" - apply plugin: 'eu.xenit.amp' apply plugin: 'java-library' - configurations { - ampArtifact - } - - artifacts { - ampArtifact amp - } - dependencies { api(project(":apix-impl")) } - publishing { - publications { - maven(MavenPublication) { - artifactId "${project.name}-amp" - artifact tasks.amp - } - } - } - sourceSets { main { java { srcDirs = ["${project.parent.projectDir}/src/main/java"] } - amp { - module { - it.put("module.id", project.name) - it.put("module.title", project.name) - it.put("module.description", - "Xenit API-X implementation Alfresco ${alfresco_version.substring(0, 3)}") - it.put("module.version", project.version) - it.put("module.repo.version.min", project.alfresco_min_version) - if(project.hasProperty("alfresco_max_version") - && project.alfresco_max_version != null) { - it.put("module.repo.version.max", project.alfresco_max_version) - } - } - - } } test { java { @@ -55,25 +21,6 @@ subprojects { testResultsDirName = "${project.parent.buildDir}/test-results/test" } } - - // Extend amp plugin task: - // We want to add 'alfresco-global.properties' etc to the module-specific folder in the AMP - // (e.g. 'config/module/alfresco/module/apix-impl-61/') without hard-coding project name for each Alfresco version. - amp { - into("config/alfresco/module/${project.name}") { - from("${project.parent.projectDir}/config/alfresco-global.properties") - from("${project.parent.projectDir}/config/log4j.properties") - from("${project.parent.projectDir}/config/module-context.xml") - expand(moduleId: project.name) - } - into("config/alfresco/module/${project.name}/messages") { - from("${project.parent.projectDir}/config/messages/") - } - } - - afterEvaluate { - signMavenPublication.dependsOn amp - } } allprojects { diff --git a/apix-rest-v1/build.gradle b/apix-rest-v1/build.gradle index a211efd6..e0a6abcc 100644 --- a/apix-rest-v1/build.gradle +++ b/apix-rest-v1/build.gradle @@ -1,20 +1,11 @@ plugins { id 'java-library' id 'idea' - id 'eu.xenit.amp' version '1.1.0' id 'eu.xenit.alfresco' version '1.1.0' } description = 'Xenit API-X Rest v1' -configurations { - ampArtifact -} - -artifacts { - ampArtifact amp -} - apply from: "$rootProject.projectDir/alfresco/70/overrides.gradle" dependencies { diff --git a/settings.gradle b/settings.gradle index 02e8d69a..ead63ac1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,8 +1,9 @@ rootProject.name = 'apix' include ':apix-interface' -include ':apix-rest-v1' include ':apix-impl' +include ':apix-rest-v1' +include ':alfresco' include ':apix-docker' include ':apix-integrationtests' include ':apix-integrationtests:model-amp' @@ -14,8 +15,10 @@ ext { for(String version : versions) { def shortVersion = version.replaceAll("\\.","") include ":apix-impl:apix-impl-$shortVersion" + include ":alfresco:$shortVersion" include ":apix-docker:docker-$shortVersion" include ":apix-integrationtests:alfresco:$shortVersion" project(":apix-impl:apix-impl-$shortVersion").projectDir = "$rootDir/apix-impl/$shortVersion" as File project(":apix-docker:docker-$shortVersion").projectDir = "$rootDir/apix-docker/$shortVersion" as File + project(":alfresco:$shortVersion").projectDir = "$rootDir/alfresco/$shortVersion" as File } \ No newline at end of file diff --git a/apix-impl/config/alfresco-global.properties b/src/config/alfresco-global.properties similarity index 100% rename from apix-impl/config/alfresco-global.properties rename to src/config/alfresco-global.properties diff --git a/apix-impl/config/log4j.properties b/src/config/log4j.properties similarity index 100% rename from apix-impl/config/log4j.properties rename to src/config/log4j.properties diff --git a/apix-impl/config/messages/faceted-search.properties b/src/config/messages/faceted-search.properties similarity index 100% rename from apix-impl/config/messages/faceted-search.properties rename to src/config/messages/faceted-search.properties diff --git a/apix-impl/config/messages/faceted-search_de.properties b/src/config/messages/faceted-search_de.properties similarity index 100% rename from apix-impl/config/messages/faceted-search_de.properties rename to src/config/messages/faceted-search_de.properties diff --git a/apix-impl/config/messages/faceted-search_en.properties b/src/config/messages/faceted-search_en.properties similarity index 100% rename from apix-impl/config/messages/faceted-search_en.properties rename to src/config/messages/faceted-search_en.properties diff --git a/apix-impl/config/messages/faceted-search_es.properties b/src/config/messages/faceted-search_es.properties similarity index 100% rename from apix-impl/config/messages/faceted-search_es.properties rename to src/config/messages/faceted-search_es.properties diff --git a/apix-impl/config/messages/faceted-search_fr.properties b/src/config/messages/faceted-search_fr.properties similarity index 100% rename from apix-impl/config/messages/faceted-search_fr.properties rename to src/config/messages/faceted-search_fr.properties diff --git a/apix-impl/config/messages/faceted-search_it.properties b/src/config/messages/faceted-search_it.properties similarity index 100% rename from apix-impl/config/messages/faceted-search_it.properties rename to src/config/messages/faceted-search_it.properties diff --git a/apix-impl/config/messages/faceted-search_ja.properties b/src/config/messages/faceted-search_ja.properties similarity index 100% rename from apix-impl/config/messages/faceted-search_ja.properties rename to src/config/messages/faceted-search_ja.properties diff --git a/apix-impl/config/messages/faceted-search_nb.properties b/src/config/messages/faceted-search_nb.properties similarity index 100% rename from apix-impl/config/messages/faceted-search_nb.properties rename to src/config/messages/faceted-search_nb.properties diff --git a/apix-impl/config/messages/faceted-search_nl.properties b/src/config/messages/faceted-search_nl.properties similarity index 100% rename from apix-impl/config/messages/faceted-search_nl.properties rename to src/config/messages/faceted-search_nl.properties diff --git a/apix-impl/config/messages/faceted-search_pt_BR.properties b/src/config/messages/faceted-search_pt_BR.properties similarity index 100% rename from apix-impl/config/messages/faceted-search_pt_BR.properties rename to src/config/messages/faceted-search_pt_BR.properties diff --git a/apix-impl/config/messages/faceted-search_ru.properties b/src/config/messages/faceted-search_ru.properties similarity index 100% rename from apix-impl/config/messages/faceted-search_ru.properties rename to src/config/messages/faceted-search_ru.properties diff --git a/apix-impl/config/messages/faceted-search_zh_CN.properties b/src/config/messages/faceted-search_zh_CN.properties similarity index 100% rename from apix-impl/config/messages/faceted-search_zh_CN.properties rename to src/config/messages/faceted-search_zh_CN.properties diff --git a/apix-impl/config/module-context.xml b/src/config/module-context.xml similarity index 100% rename from apix-impl/config/module-context.xml rename to src/config/module-context.xml From ba2c0970c1301d5906dd5539155ddd82e19bbb8c Mon Sep 17 00:00:00 2001 From: Hechmi Dammak Date: Wed, 19 Apr 2023 09:22:40 +0100 Subject: [PATCH 40/90] XENOPS-1081 change the use of request part to request param and fix bulk endpoint --- .../apix/rest/v1/bulk/BulkWebscript1.java | 105 ++- .../rest/v1/bulk/IntermediateContent.java | 55 -- .../rest/v1/bulk/IntermediateRequest.java | 72 -- .../rest/v1/bulk/IntermediateResponse.java | 84 --- .../bulk/request/BulkHttpServletRequest.java | 80 +++ .../v1/bulk/{ => request}/BulkRequest.java | 2 +- .../v1/bulk/request/IntermediateContent.java | 41 ++ .../v1/bulk/request/IntermediateRequest.java | 32 + .../DelegatingServletOutputStream.java | 61 ++ .../v1/bulk/response/HeaderValueHolder.java | 64 ++ .../v1/bulk/response/IntermediateCookie.java | 150 +++++ .../bulk/response/IntermediateResponse.java | 634 ++++++++++++++++++ .../apix/rest/v1/nodes/NodesWebscript1.java | 6 +- 13 files changed, 1115 insertions(+), 271 deletions(-) delete mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateContent.java delete mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateRequest.java delete mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateResponse.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/BulkHttpServletRequest.java rename apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/{ => request}/BulkRequest.java (95%) create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/IntermediateContent.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/IntermediateRequest.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/DelegatingServletOutputStream.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/HeaderValueHolder.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateCookie.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateResponse.java diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java index 19cca618..120e3061 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java @@ -1,78 +1,76 @@ package eu.xenit.apix.rest.v1.bulk; -import com.fasterxml.jackson.core.io.JsonStringEncoder; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.gradecak.alfresco.mvc.webscript.DispatcherWebscript; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; +import eu.xenit.apix.rest.v1.bulk.request.BulkHttpServletRequest; +import eu.xenit.apix.rest.v1.bulk.request.BulkRequest; +import eu.xenit.apix.rest.v1.bulk.request.IntermediateRequest; +import eu.xenit.apix.rest.v1.bulk.response.IntermediateResponse; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.ServiceRegistry; -import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.extensions.surf.util.Content; import org.springframework.extensions.surf.util.URLDecoder; -import org.springframework.extensions.webscripts.DeclarativeRegistry; -import org.springframework.extensions.webscripts.Match; import org.springframework.extensions.webscripts.WebScriptRequest; +import org.springframework.extensions.webscripts.servlet.WebScriptServletResponse; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + + @RestController("eu.xenit.apix.rest.v1.BulkWebscript") public class BulkWebscript1 extends ApixV1Webscript { + private static final Logger logger = LoggerFactory.getLogger(BulkWebscript1.class); + private final ServiceRegistry serviceRegistry; - private final DeclarativeRegistry wsRegistry; + final ObjectMapper mapper = new ObjectMapper(); + private final DispatcherWebscript dispatcherWebscript; public BulkWebscript1(ServiceRegistry serviceRegistry, - @Qualifier("webscripts.registry") DeclarativeRegistry wsRegistry) { + @Qualifier("alfred.api") DispatcherWebscript dispatcherWebscript) { this.serviceRegistry = serviceRegistry; - this.wsRegistry = wsRegistry; + this.dispatcherWebscript = dispatcherWebscript; } @PostMapping(value = "/v1/bulk") - public ResponseEntity bulk(@RequestBody final BulkRequest[] bulkRequests, final WebScriptRequest req) - throws IOException { + public ResponseEntity> bulk(@RequestBody final BulkRequest[] bulkRequests, + final HttpServletRequest req) { + final WebScriptRequest wsReq = ((DispatcherWebscript.WebscriptRequestWrapper) req).getWebScriptServletRequest(); - final ObjectMapper mapper = new ObjectMapper(); final List bulkResults = new ArrayList<>(); for (BulkRequest request : bulkRequests) { // v1 bulk only gets to send to other v1 endpoints :( - // We need to url decode this so we can find the match and parse any @UriVariable - final String url = URLDecoder.decode("/apix/v1" + request.getUrl()); - - logger.debug("Evaluating {} with body {}", url, request.getBody()); + // We need to url decode this, so we can find the match and parse any @UriVariable - String strippedUrl = url; - if (url.contains("?")) { - strippedUrl = url.substring(0, url.indexOf("?")); - } + BulkHttpServletRequest bulkHttpServletRequest = new BulkHttpServletRequest(req, + URLDecoder.decode("/alfresco/service/apix/v1" + request.getUrl()), + request.getMethod().toUpperCase(), request.getBody()); + logger.debug("Evaluating {} with body {} and method {}", bulkHttpServletRequest.getRequestURI(), + bulkHttpServletRequest.getBody(), + bulkHttpServletRequest.getMethod()); - //The Match created in this method does not split off the querystring arguments correctly, - //therefore we will remove the queryString from the url for this method. Later in the call, - //the url with query string is still passed to have it handled. - final Match m = wsRegistry.findWebScript(request.getMethod(), strippedUrl); - if (m == null || m.getWebScript() == null) { - logger.debug("Could not find any webscript bound to {}. Injecting 404 subresponse.", url); - bulkResults.add(create404subResult(mapper, url)); - continue; - } + final IntermediateRequest intermediateRequest = new IntermediateRequest(wsReq, bulkHttpServletRequest, + null); - logger.debug("Matched on {}", m.getWebScript().getClass()); + final IntermediateResponse mockRes = new IntermediateResponse(); + final WebScriptServletResponse intermediateResponse = new WebScriptServletResponse(wsReq.getRuntime(), + mockRes); - // These Intermediate... classes are simple container objects, standing in for HTTP requests and responses - // They are used to execute the WebScript directly, providing arguments and retrieving the result - Content intermediateContent = new IntermediateContent(req.getContent(), request.getBody()); - final WebScriptRequest intermediateRequest = new IntermediateRequest(req, url, intermediateContent, m); - final IntermediateResponse intermediateResponse = new IntermediateResponse(req.getRuntime()); // Each subrequest gets to run in its own transaction context, because even a caught exception can mark a // transaction as "needs to be rolled back". We don't want a previous subrequest to be rolled back because @@ -81,28 +79,28 @@ public ResponseEntity bulk(@RequestBody final BulkRequest[] bulkRequests, fin .doInTransaction((RetryingTransactionHelper.RetryingTransactionCallback) () -> { try { // Actual execution of called WebScript happens here - m.getWebScript().execute(intermediateRequest, intermediateResponse); - logger.debug("Resp body is '{}'", intermediateResponse.getWriter().toString()); + dispatcherWebscript.execute(intermediateRequest, intermediateResponse); + logger.debug("Resp body is '{}'", intermediateResponse.getWriter()); // Convert the response container to json + statuscode + headers - return createBulkResult(mapper, intermediateResponse); + return createBulkResult(mapper, mockRes); } catch (Exception e) { // Catching all exceptions to just print a stacktrace isn't super clean... // But we want the bulk to continue with the other requests even if this one fails. - logger.error("Error in bulk call to {}", url, e); + logger.error("Error in bulk call to {}", intermediateRequest.getHttpServletRequest().getRequestURI(), e); return new BulkSubResult(500, - new ObjectMapper().valueToTree("Exception found: " + e.getMessage()), + mapper.valueToTree("Exception found: " + e.getMessage()), new HashMap<>()); } }, false, true); if (subRes == null) { - logger.warn("bulkSubResult is null for request {}.", url); + logger.warn("bulkSubResult is null for request {}.", intermediateRequest.getHttpServletRequest().getRequestURI()); } else { bulkResults.add(subRes); } } - if (bulkResults.size() > 0) { + if (!bulkResults.isEmpty()) { // Write out the list of BulkSubResults which becomes nice json return writeJsonResponse(bulkResults); } @@ -113,21 +111,16 @@ public ResponseEntity bulk(@RequestBody final BulkRequest[] bulkRequests, fin private static BulkSubResult createBulkResult(ObjectMapper mapper, IntermediateResponse resp) throws IOException { int status = resp.getStatus(); JsonNode body; - String strbody = resp.getWriter().toString(); - - if (strbody == null || strbody.equals("")) { + String strBody = resp.getContentAsString(); + if (strBody == null || strBody.equals("")) { body = mapper.createObjectNode(); } else { - body = mapper.readTree(resp.getWriter().toString()); + body = mapper.readTree(strBody); } - return new BulkSubResult(status, body, resp.getHeaders()); + return new BulkSubResult(status, body, resp.getHeaderNames().stream().collect( + Collectors.toMap(Function.identity(), resp::getHeader) + )); } - private static BulkSubResult create404subResult(ObjectMapper mapper, String url) throws IOException { - return new BulkSubResult(HttpStatus.SC_NOT_FOUND /* = 404 */, - mapper.readTree("\"No Webscript found for url " + - new String(JsonStringEncoder.getInstance().quoteAsString(url)) + "\""), - new HashMap<>(0)); - } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateContent.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateContent.java deleted file mode 100644 index 7e10bedf..00000000 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateContent.java +++ /dev/null @@ -1,55 +0,0 @@ -package eu.xenit.apix.rest.v1.bulk; - -import com.fasterxml.jackson.databind.JsonNode; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; -import java.nio.charset.StandardCharsets; - -import org.apache.commons.io.IOUtils; -import org.springframework.extensions.surf.util.Content; - -public class IntermediateContent implements Content { - - // According to /etc/mime.types, this is the only one - private final String mimetype = "application/json"; - private String json; - // Should always be UTF-8 but since our json comes from the parent Content, - // we'll get the encoding from there too - private String encoding; - - public IntermediateContent(Content parent, JsonNode content) { - json = (content != null) ? content.toString() : "{}"; - encoding = parent.getEncoding(); - } - - public String getContent() { - return json; - } - - @Override - public String getMimetype() { - return mimetype; - } - - @Override - public String getEncoding() { - return encoding; - } - - @Override - public long getSize() { - return json.length(); - } - - @Override - public InputStream getInputStream() { - return IOUtils.toInputStream(json, StandardCharsets.UTF_8); - } - - @Override - public Reader getReader() throws IOException { - return new StringReader(json); - } -} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateRequest.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateRequest.java deleted file mode 100644 index 22d5bbd3..00000000 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateRequest.java +++ /dev/null @@ -1,72 +0,0 @@ -package eu.xenit.apix.rest.v1.bulk; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.springframework.extensions.surf.util.Content; -import org.springframework.extensions.webscripts.Match; -import org.springframework.extensions.webscripts.WebScriptRequest; -import org.springframework.extensions.webscripts.WebScriptRequestURLImpl; - -public class IntermediateRequest extends WebScriptRequestURLImpl { - - private String serverPath; - private Map> headers; - private String agent; - private Content content; - - public IntermediateRequest(WebScriptRequest bulkWebScriptRequest, String URL, Content content, Match match) { - super(bulkWebScriptRequest.getRuntime(), splitURL(bulkWebScriptRequest.getContextPath(), URL), match); - serverPath = bulkWebScriptRequest.getServerPath(); - this.content = content; - agent = bulkWebScriptRequest.getAgent(); - headers = new HashMap<>(); - for (String headerName : bulkWebScriptRequest.getHeaderNames()) { - String[] values = bulkWebScriptRequest.getHeaderValues(headerName); - List list = Arrays.asList(values); - headers.put(headerName, list); - } - } - - @Override - public String getServerPath() { - return serverPath; - } - - @Override - public String[] getHeaderNames() { - Set names = headers.keySet(); - return names.toArray(new String[names.size()]); - } - - @Override - public String getHeader(String name) { - List list = headers.get(name); - if (list == null || list.size() == 0) { - return null; - } - return list.get(0); - } - - @Override - public String[] getHeaderValues(String name) { - List list = headers.get(name); - if (list == null || list.size() == 0) { - return null; - } - return list.toArray(new String[list.size()]); - } - - @Override - public Content getContent() { - return content; - } - - @Override - public String getAgent() { - return agent; - } - -} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateResponse.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateResponse.java deleted file mode 100644 index 478c62d5..00000000 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/IntermediateResponse.java +++ /dev/null @@ -1,84 +0,0 @@ -package eu.xenit.apix.rest.v1.bulk; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.StringWriter; -import java.io.Writer; -import java.util.HashMap; -import java.util.Map; -import org.springframework.extensions.webscripts.Cache; -import org.springframework.extensions.webscripts.Runtime; -import org.springframework.extensions.webscripts.WebScriptResponseImpl; - -public class IntermediateResponse extends WebScriptResponseImpl { - - private Writer out; - private int status = 200; // Webscripts default to success, explicit set status on failure - private Map headers; - - public IntermediateResponse(Runtime runtime) { - super(runtime); - out = new StringWriter(); - headers = new HashMap<>(); - } - - public int getStatus() { - return status; - } - - public void setStatus(int status) { - this.status = status; - } - - public OutputStream getOutputStream() throws IOException { - // TODO: implement this? - return null; - } - - public Writer getWriter() throws IOException { - return out; - } - - public Map getHeaders() { - return headers; - } - - public void setHeader(String name, String value) { - headers.put(name, value); - } - - public void addHeader(String name, String value) { - setHeader(name, value); - } - - public String encodeScriptUrl(String url) { - // not supported - throw new UnsupportedOperationException(); - } - - public String getEncodeScriptUrlFunction(String name) { - // not supported - throw new UnsupportedOperationException(); - } - - public void reset() { - // not supported - } - - public void reset(String preserveHeadersPattern) { - // not supported - } - - public void setCache(Cache cache) { - // not supported - } - - public void setContentType(String contentType) { - // not supported - } - - public void setContentEncoding(String contentEncoding) { - // not supported - } - -} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/BulkHttpServletRequest.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/BulkHttpServletRequest.java new file mode 100644 index 00000000..6cdec4eb --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/BulkHttpServletRequest.java @@ -0,0 +1,80 @@ +package eu.xenit.apix.rest.v1.bulk.request; + +import org.springframework.util.StringUtils; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.IOException; + +public class BulkHttpServletRequest extends HttpServletRequestWrapper { + private static final String HTTP = "http"; + + private static final String HTTPS = "https"; + private static final String ALFRESCO = "/alfresco"; + private static final String SERVICE = "/service"; + + /** + * Constructs a request object wrapping the given request. + * + * @param request the {@link HttpServletRequest} to be wrapped. + * @throws IllegalArgumentException if the request is null + */ + public BulkHttpServletRequest(HttpServletRequest request, String url, String method, Object body) { + super(request); + this.url = url; + this.method = method; + this.body = body; + } + + final String url; + final String method; + final Object body; + + @Override + public String getRequestURI() { + return url; + } + + @Override + public String getContextPath() { + return ALFRESCO; + } + + @Override + public String getServletPath() { + return SERVICE; + } + + @Override + public String getMethod() { + return method; + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return new IntermediateContent(body); + } + + public Object getBody() { + return body; + } + + @Override + public StringBuffer getRequestURL() { + String scheme = getScheme(); + String server = getServerName(); + int port = getServerPort(); + String uri = getRequestURI(); + + StringBuffer sb = new StringBuffer(scheme).append("://").append(server); + if (port > 0 && ((HTTP.equalsIgnoreCase(scheme) && port != 80) || + (HTTPS.equalsIgnoreCase(scheme) && port != 443))) { + sb.append(':').append(port); + } + if (StringUtils.hasText(uri)) { + sb.append(uri); + } + return sb; + } +} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkRequest.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/BulkRequest.java similarity index 95% rename from apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkRequest.java rename to apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/BulkRequest.java index 0b04e280..a3ec58a3 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkRequest.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/BulkRequest.java @@ -1,4 +1,4 @@ -package eu.xenit.apix.rest.v1.bulk; +package eu.xenit.apix.rest.v1.bulk.request; import com.fasterxml.jackson.databind.JsonNode; diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/IntermediateContent.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/IntermediateContent.java new file mode 100644 index 00000000..7887cdbf --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/IntermediateContent.java @@ -0,0 +1,41 @@ +package eu.xenit.apix.rest.v1.bulk.request; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class IntermediateContent extends ServletInputStream { + IntermediateContent(Object body) throws JsonProcessingException { + mapper = new ObjectMapper(); + delegate = new ByteArrayInputStream(mapper.writeValueAsBytes(body)); + } + + final ObjectMapper mapper; + final InputStream delegate; + + @Override + public int read() throws IOException { + return delegate.read(); + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener readListener) { + //will not be implemented + } + +} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/IntermediateRequest.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/IntermediateRequest.java new file mode 100644 index 00000000..7ec4ab27 --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/IntermediateRequest.java @@ -0,0 +1,32 @@ +package eu.xenit.apix.rest.v1.bulk.request; + +import org.springframework.extensions.webscripts.Match; +import org.springframework.extensions.webscripts.WebScriptRequest; +import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class IntermediateRequest extends WebScriptServletRequest { + + + public IntermediateRequest(WebScriptRequest bulkWebScriptRequest, HttpServletRequest request, Match match) { + super(bulkWebScriptRequest.getRuntime(), request, match, null); + } + + + @Override + public String getExtensionPath() { + String uri = getHttpServletRequest().getRequestURI(); + List uriSplit = new ArrayList<>(Arrays.asList(uri.split("/"))); + uriSplit.remove(0); + uriSplit.remove(0); + uriSplit.remove(0); + uriSplit.remove(0); + return String.join("/", uriSplit); + } + + +} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/DelegatingServletOutputStream.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/DelegatingServletOutputStream.java new file mode 100644 index 00000000..759a73e9 --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/DelegatingServletOutputStream.java @@ -0,0 +1,61 @@ +package eu.xenit.apix.rest.v1.bulk.response; + + +import org.springframework.util.Assert; + +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; +import java.io.IOException; +import java.io.OutputStream; + +public class DelegatingServletOutputStream extends ServletOutputStream { + + private final OutputStream targetStream; + + + /** + * Create a DelegatingServletOutputStream for the given target stream. + * + * @param targetStream the target stream (never {@code null}) + */ + public DelegatingServletOutputStream(OutputStream targetStream) { + Assert.notNull(targetStream, "Target OutputStream must not be null"); + this.targetStream = targetStream; + } + + /** + * Return the underlying target stream (never {@code null}). + */ + public final OutputStream getTargetStream() { + return this.targetStream; + } + + + @Override + public void write(int b) throws IOException { + this.targetStream.write(b); + } + + @Override + public void flush() throws IOException { + super.flush(); + this.targetStream.flush(); + } + + @Override + public void close() throws IOException { + super.close(); + this.targetStream.close(); + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + throw new UnsupportedOperationException(); + } + +} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/HeaderValueHolder.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/HeaderValueHolder.java new file mode 100644 index 00000000..e6364e24 --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/HeaderValueHolder.java @@ -0,0 +1,64 @@ +package eu.xenit.apix.rest.v1.bulk.response; + + +import org.springframework.lang.Nullable; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class HeaderValueHolder { + + private final List values = new LinkedList<>(); + + + void setValue(@Nullable Object value) { + this.values.clear(); + if (value != null) { + this.values.add(value); + } + } + + void addValue(Object value) { + this.values.add(value); + } + + void addValues(Collection values) { + this.values.addAll(values); + } + + void addValueArray(Object values) { + CollectionUtils.mergeArrayIntoCollection(values, this.values); + } + + List getValues() { + return Collections.unmodifiableList(this.values); + } + + List getStringValues() { + List stringList = new ArrayList<>(this.values.size()); + for (Object value : this.values) { + stringList.add(value.toString()); + } + return Collections.unmodifiableList(stringList); + } + + @Nullable + Object getValue() { + return (!this.values.isEmpty() ? this.values.get(0) : null); + } + + @Nullable + String getStringValue() { + return (!this.values.isEmpty() ? String.valueOf(this.values.get(0)) : null); + } + + @Override + public String toString() { + return this.values.toString(); + } + +} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateCookie.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateCookie.java new file mode 100644 index 00000000..b9190a86 --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateCookie.java @@ -0,0 +1,150 @@ +package eu.xenit.apix.rest.v1.bulk.response; + +import org.springframework.core.style.ToStringCreator; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import javax.servlet.http.Cookie; +import java.time.DateTimeException; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + + +public class IntermediateCookie extends Cookie { + + private static final long serialVersionUID = 4312531139502726325L; + + + @Nullable + private ZonedDateTime expires; + + @Nullable + private String sameSite; + + + /** + * Construct a new {@link IntermediateCookie} with the supplied name and value. + * + * @param name the name + * @param value the value + * @see Cookie#Cookie(String, String) + */ + public IntermediateCookie(String name, String value) { + super(name, value); + } + + /** + * Set the "Expires" attribute for this cookie. + * + * @since 5.1.11 + */ + public void setExpires(@Nullable ZonedDateTime expires) { + this.expires = expires; + } + + /** + * Get the "Expires" attribute for this cookie. + * + * @return the "Expires" attribute for this cookie, or {@code null} if not set + * @since 5.1.11 + */ + @Nullable + public ZonedDateTime getExpires() { + return this.expires; + } + + /** + * Set the "SameSite" attribute for this cookie. + *

This limits the scope of the cookie such that it will only be attached + * to same-site requests if the supplied value is {@code "Strict"} or cross-site + * requests if the supplied value is {@code "Lax"}. + * + * @see RFC6265 bis + */ + public void setSameSite(@Nullable String sameSite) { + this.sameSite = sameSite; + } + + /** + * Get the "SameSite" attribute for this cookie. + * + * @return the "SameSite" attribute for this cookie, or {@code null} if not set + */ + @Nullable + public String getSameSite() { + return this.sameSite; + } + + + /** + * Factory method that parses the value of the supplied "Set-Cookie" header. + * + * @param setCookieHeader the "Set-Cookie" value; never {@code null} or empty + * @return the created cookie + */ + public static IntermediateCookie parse(String setCookieHeader) { + Assert.notNull(setCookieHeader, "Set-Cookie header must not be null"); + String[] cookieParts = setCookieHeader.split("\\s*=\\s*", 2); + Assert.isTrue(cookieParts.length == 2, () -> "Invalid Set-Cookie header '" + setCookieHeader + "'"); + + String name = cookieParts[0]; + String[] valueAndAttributes = cookieParts[1].split("\\s*;\\s*", 2); + String value = valueAndAttributes[0]; + String[] attributes = + (valueAndAttributes.length > 1 ? valueAndAttributes[1].split("\\s*;\\s*") : new String[0]); + + IntermediateCookie cookie = new IntermediateCookie(name, value); + for (String attribute : attributes) { + if (StringUtils.startsWithIgnoreCase(attribute, "Domain")) { + cookie.setDomain(extractAttributeValue(attribute, setCookieHeader)); + } else if (StringUtils.startsWithIgnoreCase(attribute, "Max-Age")) { + cookie.setMaxAge(Integer.parseInt(extractAttributeValue(attribute, setCookieHeader))); + } else if (StringUtils.startsWithIgnoreCase(attribute, "Expires")) { + try { + cookie.setExpires(ZonedDateTime.parse(extractAttributeValue(attribute, setCookieHeader), + DateTimeFormatter.RFC_1123_DATE_TIME)); + } catch (DateTimeException ex) { + // ignore invalid date formats + } + } else if (StringUtils.startsWithIgnoreCase(attribute, "Path")) { + cookie.setPath(extractAttributeValue(attribute, setCookieHeader)); + } else if (StringUtils.startsWithIgnoreCase(attribute, "Secure")) { + cookie.setSecure(true); + } else if (StringUtils.startsWithIgnoreCase(attribute, "HttpOnly")) { + cookie.setHttpOnly(true); + } else if (StringUtils.startsWithIgnoreCase(attribute, "SameSite")) { + cookie.setSameSite(extractAttributeValue(attribute, setCookieHeader)); + } else if (StringUtils.startsWithIgnoreCase(attribute, "Comment")) { + cookie.setComment(extractAttributeValue(attribute, setCookieHeader)); + } + } + return cookie; + } + + private static String extractAttributeValue(String attribute, String header) { + String[] nameAndValue = attribute.split("="); + Assert.isTrue(nameAndValue.length == 2, + () -> "No value in attribute '" + nameAndValue[0] + "' for Set-Cookie header '" + header + "'"); + return nameAndValue[1]; + } + + @Override + public String toString() { + return new ToStringCreator(this) + .append("name", getName()) + .append("value", getValue()) + .append("Path", getPath()) + .append("Domain", getDomain()) + .append("Version", getVersion()) + .append("Comment", getComment()) + .append("Secure", getSecure()) + .append("HttpOnly", isHttpOnly()) + .append("SameSite", this.sameSite) + .append("Max-Age", getMaxAge()) + .append("Expires", (this.expires != null ? + DateTimeFormatter.RFC_1123_DATE_TIME.format(this.expires) : null)) + .toString(); + } + +} \ No newline at end of file diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateResponse.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateResponse.java new file mode 100644 index 00000000..a240c31f --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateResponse.java @@ -0,0 +1,634 @@ +package eu.xenit.apix.rest.v1.bulk.response; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; +import org.springframework.util.StringUtils; +import org.springframework.web.util.WebUtils; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; + + +public class IntermediateResponse implements HttpServletResponse { + + private static final String CHARSET_PREFIX = "charset="; + + private static final String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz"; + + private static final TimeZone GMT = TimeZone.getTimeZone("GMT"); + + + //--------------------------------------------------------------------- + // ServletResponse properties + //--------------------------------------------------------------------- + + + private String characterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING; + + /** + * {@code true} if the character encoding has been explicitly set through + * {@link HttpServletResponse} methods or through a {@code charset} parameter + * on the {@code Content-Type}. + */ + private boolean characterEncodingSet = false; + + private final ByteArrayOutputStream content = new ByteArrayOutputStream(1024); + + private final ServletOutputStream outputStream = new ResponseServletOutputStream(this.content); + + @Nullable + private PrintWriter writer; + + + @Nullable + private String contentType; + + private int bufferSize = 4096; + + private boolean committed; + + private Locale locale = Locale.getDefault(); + + + //--------------------------------------------------------------------- + // HttpServletResponse properties + //--------------------------------------------------------------------- + + + private final Map headers = new LinkedCaseInsensitiveMap<>(); + + private int status = HttpServletResponse.SC_OK; + + + //--------------------------------------------------------------------- + // ServletResponse interface + //--------------------------------------------------------------------- + + + @Override + public void setCharacterEncoding(String characterEncoding) { + setExplicitCharacterEncoding(characterEncoding); + updateContentTypePropertyAndHeader(); + } + + private void setExplicitCharacterEncoding(String characterEncoding) { + Assert.notNull(characterEncoding, "'characterEncoding' must not be null"); + this.characterEncoding = characterEncoding; + this.characterEncodingSet = true; + } + + private void updateContentTypePropertyAndHeader() { + if (this.contentType != null) { + String value = this.contentType; + if (this.characterEncodingSet && !value.toLowerCase().contains(CHARSET_PREFIX)) { + value += ';' + CHARSET_PREFIX + getCharacterEncoding(); + this.contentType = value; + } + doAddHeaderValue(HttpHeaders.CONTENT_TYPE, value, true); + } + } + + @Override + public String getCharacterEncoding() { + return this.characterEncoding; + } + + @Override + public ServletOutputStream getOutputStream() { + boolean outputStreamAccessAllowed = true; + Assert.state(outputStreamAccessAllowed, "OutputStream access not allowed"); + return this.outputStream; + } + + @Override + public PrintWriter getWriter() throws UnsupportedEncodingException { + boolean writerAccessAllowed = true; + Assert.state(writerAccessAllowed, "Writer access not allowed"); + if (this.writer == null) { + Writer targetWriter = new OutputStreamWriter(this.content, getCharacterEncoding()); + this.writer = new ResponsePrintWriter(targetWriter); + } + return this.writer; + } + + + /** + * Get the content of the response body as a {@code String}, using the charset + * specified for the response by the application, either through + * {@link HttpServletResponse} methods or through a charset parameter on the + * {@code Content-Type}. If no charset has been explicitly defined, they + * will be used. + * + * @return the content as a {@code String} + * @throws UnsupportedEncodingException if the character encoding is not supported + * @see #setCharacterEncoding(String) + * @see #setContentType(String) + */ + public String getContentAsString() throws UnsupportedEncodingException { + return this.content.toString(getCharacterEncoding()); + } + + + @Override + public void setContentLength(int contentLength) { + doAddHeaderValue(HttpHeaders.CONTENT_LENGTH, contentLength, true); + } + + + @Override + public void setContentLengthLong(long contentLength) { + doAddHeaderValue(HttpHeaders.CONTENT_LENGTH, contentLength, true); + } + + + @Override + public void setContentType(@Nullable String contentType) { + this.contentType = contentType; + if (contentType != null) { + try { + MediaType mediaType = MediaType.parseMediaType(contentType); + if (mediaType.getCharset() != null) { + setExplicitCharacterEncoding(mediaType.getCharset().name()); + } + } catch (Exception ex) { + // Try to get charset value anyway + int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX); + if (charsetIndex != -1) { + setExplicitCharacterEncoding(contentType.substring(charsetIndex + CHARSET_PREFIX.length())); + } + } + updateContentTypePropertyAndHeader(); + } + } + + @Override + @Nullable + public String getContentType() { + return this.contentType; + } + + @Override + public void setBufferSize(int bufferSize) { + this.bufferSize = bufferSize; + } + + @Override + public int getBufferSize() { + return this.bufferSize; + } + + @Override + public void flushBuffer() { + setCommitted(true); + } + + @Override + public void resetBuffer() { + Assert.state(!isCommitted(), "Cannot reset buffer - response is already committed"); + this.content.reset(); + } + + private void setCommittedIfBufferSizeExceeded() { + int bufSize = getBufferSize(); + if (bufSize > 0 && this.content.size() > bufSize) { + setCommitted(true); + } + } + + public void setCommitted(boolean committed) { + this.committed = committed; + } + + @Override + public boolean isCommitted() { + return this.committed; + } + + @Override + public void reset() { + resetBuffer(); + this.characterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING; + this.characterEncodingSet = false; + this.contentType = null; + this.locale = Locale.getDefault(); + this.headers.clear(); + this.status = HttpServletResponse.SC_OK; + } + + @Override + public void setLocale(@Nullable Locale locale) { + // Although the Javadoc for javax.servlet.ServletResponse.setLocale(Locale) does not + // state how a null value for the supplied Locale should be handled, both Tomcat and + // Jetty simply ignore a null value. So we do the same here. + if (locale == null) { + return; + } + this.locale = locale; + doAddHeaderValue(HttpHeaders.CONTENT_LANGUAGE, locale.toLanguageTag(), true); + } + + @Override + public Locale getLocale() { + return this.locale; + } + + + //--------------------------------------------------------------------- + // HttpServletResponse interface + //--------------------------------------------------------------------- + + @Override + public void addCookie(Cookie cookie) { + Assert.notNull(cookie, "Cookie must not be null"); + doAddHeaderValue(HttpHeaders.SET_COOKIE, getCookieHeader(cookie), false); + } + + private String getCookieHeader(Cookie cookie) { + StringBuilder buf = new StringBuilder(); + buf.append(cookie.getName()).append('=').append(cookie.getValue() == null ? "" : cookie.getValue()); + if (StringUtils.hasText(cookie.getPath())) { + buf.append("; Path=").append(cookie.getPath()); + } + if (StringUtils.hasText(cookie.getDomain())) { + buf.append("; Domain=").append(cookie.getDomain()); + } + int maxAge = cookie.getMaxAge(); + ZonedDateTime expires = (cookie instanceof IntermediateCookie ? ((IntermediateCookie) cookie).getExpires() : null); + if (maxAge >= 0) { + buf.append("; Max-Age=").append(maxAge); + buf.append("; Expires="); + if (expires != null) { + buf.append(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME)); + } else { + HttpHeaders headers = new HttpHeaders(); + headers.setExpires(maxAge > 0 ? System.currentTimeMillis() + 1000L * maxAge : 0); + buf.append(headers.getFirst(HttpHeaders.EXPIRES)); + } + } else if (expires != null) { + buf.append("; Expires="); + buf.append(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME)); + } + + if (cookie.getSecure()) { + buf.append("; Secure"); + } + if (cookie.isHttpOnly()) { + buf.append("; HttpOnly"); + } + if (cookie instanceof IntermediateCookie) { + IntermediateCookie intermediateCookie = (IntermediateCookie) cookie; + if (StringUtils.hasText(intermediateCookie.getSameSite())) { + buf.append("; SameSite=").append(intermediateCookie.getSameSite()); + } + } + if (StringUtils.hasText(cookie.getComment())) { + buf.append("; Comment=").append(cookie.getComment()); + } + return buf.toString(); + } + + + @Override + public boolean containsHeader(String name) { + return this.headers.containsKey(name); + } + + /** + * Return the names of all specified headers as a Set of Strings. + *

As of Servlet 3.0, this method is also defined in {@link HttpServletResponse}. + * + * @return the {@code Set} of header name {@code Strings}, or an empty {@code Set} if none + */ + @Override + public Collection getHeaderNames() { + return this.headers.keySet(); + } + + /** + * Return the primary value for the given header as a String, if any. + * Will return the first value in case of multiple values. + *

As of Servlet 3.0, this method is also defined in {@link HttpServletResponse}. + * As of Spring 3.1, it returns a stringified value for Servlet 3.0 compatibility. + * + * @param name the name of the header + * @return the associated header value, or {@code null} if none + */ + @Override + @Nullable + public String getHeader(String name) { + HeaderValueHolder header = this.headers.get(name); + return (header != null ? header.getStringValue() : null); + } + + /** + * Return all values for the given header as a List of Strings. + *

As of Servlet 3.0, this method is also defined in {@link HttpServletResponse}. + * As of Spring 3.1, it returns a List of stringified values for Servlet 3.0 compatibility. + * + * @param name the name of the header + * @return the associated header values, or an empty List if none + */ + @Override + public List getHeaders(String name) { + HeaderValueHolder header = this.headers.get(name); + if (header != null) { + return header.getStringValues(); + } else { + return Collections.emptyList(); + } + } + + /** + * The default implementation returns the given URL String as-is. + *

Can be overridden in subclasses, appending a session id or the like. + */ + @Override + public String encodeURL(String url) { + return url; + } + + /** + * The default implementation delegates to {@link #encodeURL}, + * returning the given URL String as-is. + *

Can be overridden in subclasses, appending a session id or the like + * in a redirect-specific fashion. For general URL encoding rules, + * override the common {@link #encodeURL} method instead, applying + * to redirect URLs as well as to general URLs. + */ + @Override + public String encodeRedirectURL(String url) { + return encodeURL(url); + } + + @Override + @Deprecated + public String encodeUrl(String url) { + return encodeURL(url); + } + + @Override + @Deprecated + public String encodeRedirectUrl(String url) { + return encodeRedirectURL(url); + } + + @Override + public void sendError(int status, String errorMessage) throws UnsupportedEncodingException { + Assert.state(!isCommitted(), "Cannot set error status - response is already committed"); + this.status = status; + getWriter().println(errorMessage); + setCommitted(true); + } + + @Override + public void sendError(int status) { + Assert.state(!isCommitted(), "Cannot set error status - response is already committed"); + this.status = status; + setCommitted(true); + } + + @Override + public void sendRedirect(String url) { + Assert.state(!isCommitted(), "Cannot send redirect - response is already committed"); + Assert.notNull(url, "Redirect URL must not be null"); + setHeader(HttpHeaders.LOCATION, url); + setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + setCommitted(true); + } + + + @Override + public void setDateHeader(String name, long value) { + setHeaderValue(name, formatDate(value)); + } + + @Override + public void addDateHeader(String name, long value) { + addHeaderValue(name, formatDate(value)); + } + + + private String formatDate(long date) { + return newDateFormat().format(new Date(date)); + } + + private DateFormat newDateFormat() { + SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.US); + dateFormat.setTimeZone(GMT); + return dateFormat; + } + + @Override + public void setHeader(String name, @Nullable String value) { + setHeaderValue(name, value); + } + + @Override + public void addHeader(String name, @Nullable String value) { + addHeaderValue(name, value); + } + + @Override + public void setIntHeader(String name, int value) { + setHeaderValue(name, value); + } + + @Override + public void addIntHeader(String name, int value) { + addHeaderValue(name, value); + } + + private void setHeaderValue(String name, @Nullable Object value) { + if (value == null) { + return; + } + boolean replaceHeader = true; + if (setSpecialHeader(name, value, replaceHeader)) { + return; + } + doAddHeaderValue(name, value, replaceHeader); + } + + private void addHeaderValue(String name, @Nullable Object value) { + if (value == null) { + return; + } + boolean replaceHeader = false; + if (setSpecialHeader(name, value, replaceHeader)) { + return; + } + doAddHeaderValue(name, value, replaceHeader); + } + + private boolean setSpecialHeader(String name, Object value, boolean replaceHeader) { + if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(name)) { + setContentType(value.toString()); + return true; + } else if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name)) { + setContentLength(value instanceof Number ? ((Number) value).intValue() : Integer.parseInt(value.toString())); + return true; + } else if (HttpHeaders.CONTENT_LANGUAGE.equalsIgnoreCase(name)) { + String contentLanguages = value.toString(); + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_LANGUAGE, contentLanguages); + Locale language = headers.getContentLanguage(); + setLocale(language != null ? language : Locale.getDefault()); + // Since setLocale() sets the Content-Language header to the given + // single Locale, we have to explicitly set the Content-Language header + // to the user-provided value. + doAddHeaderValue(HttpHeaders.CONTENT_LANGUAGE, contentLanguages, true); + return true; + } else if (HttpHeaders.SET_COOKIE.equalsIgnoreCase(name)) { + IntermediateCookie cookie = IntermediateCookie.parse(value.toString()); + if (replaceHeader) { + setCookie(cookie); + } else { + addCookie(cookie); + } + return true; + } else { + return false; + } + } + + private void doAddHeaderValue(String name, Object value, boolean replace) { + Assert.notNull(value, "Header value must not be null"); + HeaderValueHolder header = this.headers.computeIfAbsent(name, key -> new HeaderValueHolder()); + if (replace) { + header.setValue(value); + } else { + header.addValue(value); + } + } + + /** + * Set the {@code Set-Cookie} header to the supplied {@link Cookie}, + * overwriting any previous cookies. + * + * @param cookie the {@code Cookie} to set + * @see #addCookie(Cookie) + * @since 5.1.10 + */ + private void setCookie(Cookie cookie) { + Assert.notNull(cookie, "Cookie must not be null"); + doAddHeaderValue(HttpHeaders.SET_COOKIE, getCookieHeader(cookie), true); + } + + @Override + public void setStatus(int status) { + if (!this.isCommitted()) { + this.status = status; + } + } + + @Override + @Deprecated + public void setStatus(int status, String errorMessage) { + if (!this.isCommitted()) { + this.status = status; + try { + getWriter().println(errorMessage); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + } + + @Override + public int getStatus() { + return this.status; + } + + + /** + * Inner class that adapts the ServletOutputStream to mark the + * response as committed once the buffer size is exceeded. + */ + private class ResponseServletOutputStream extends DelegatingServletOutputStream { + + public ResponseServletOutputStream(OutputStream out) { + super(out); + } + + @Override + public void write(int b) throws IOException { + super.write(b); + super.flush(); + setCommittedIfBufferSizeExceeded(); + } + + @Override + public void flush() throws IOException { + super.flush(); + setCommitted(true); + } + } + + /** + * Inner class that adapts the PrintWriter to mark the + * response as committed once the buffer size is exceeded. + */ + private class ResponsePrintWriter extends PrintWriter { + + public ResponsePrintWriter(Writer out) { + super(out, true); + } + + @Override + public void write(char[] buf, int off, int len) { + super.write(buf, off, len); + super.flush(); + setCommittedIfBufferSizeExceeded(); + } + + @Override + public void write(String s, int off, int len) { + super.write(s, off, len); + super.flush(); + setCommittedIfBufferSizeExceeded(); + } + + @Override + public void write(int c) { + super.write(c); + super.flush(); + setCommittedIfBufferSizeExceeded(); + } + + @Override + public void flush() { + super.flush(); + setCommitted(true); + } + + @Override + public void close() { + super.flush(); + super.close(); + setCommitted(true); + } + } + +} \ No newline at end of file diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java index 17bc59f0..b13a378b 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java @@ -593,9 +593,9 @@ public ResponseEntity exists(@PathVariable String space, @PathVariable @PostMapping(value = "/v1/nodes/upload") public ResponseEntity uploadNode( - @RequestPart(required = false) String type, - @RequestPart(required = false) String parent, - @RequestPart(required = false) Boolean extractMetadata, + @RequestParam(required = false) String type, + @RequestParam(required = false) String parent, + @RequestParam(required = false) Boolean extractMetadata, @RequestPart(required = false) MetadataChanges metadata, @RequestPart final MultipartFile file) { RetryingTransactionHelper transactionHelper = serviceRegistry.getRetryingTransactionHelper(); From 51d70ed4718eef19a63165ff69d0c3772b406057 Mon Sep 17 00:00:00 2001 From: Hechmi Dammak Date: Wed, 19 Apr 2023 12:40:31 +0100 Subject: [PATCH 41/90] XENOPS-1081 refactor code and remove the use of object mapper instead of jackson in request body --- .../apix/rest/v1/tests/NodesBaseTest.java | 24 +-- .../xenit/apix/rest/v1/ApixV1Webscript.java | 41 +++-- .../apix/rest/v1/bulk/BulkSubResult.java | 6 +- .../apix/rest/v1/bulk/BulkWebscript1.java | 23 +-- .../v1/bulk/request/IntermediateRequest.java | 26 +-- .../apix/rest/v1/nodes/AncestorsObject.java | 16 +- .../apix/rest/v1/nodes/ChangeAclsOptions.java | 8 +- .../rest/v1/nodes/ChangeParentOptions.java | 16 +- .../v1/nodes/CreateAssociationOptions.java | 7 + .../apix/rest/v1/nodes/CreateNodeOptions.java | 91 ++++++---- .../apix/rest/v1/nodes/InheritFromParent.java | 12 +- .../eu/xenit/apix/rest/v1/nodes/NodeInfo.java | 50 +++++- .../apix/rest/v1/nodes/NodeInfoRequest.java | 119 +++++++++++++ .../apix/rest/v1/nodes/NodesWebscript1.java | 145 +++++----------- .../eu/xenit/apix/rest/v1/temp/Charsets.java | 61 ------- .../rest/v1/temp/ReversedLinesFileReader.java | 29 ++-- .../xenit/apix/rest/v2/ApixV2Webscript.java | 158 +++++++++--------- .../apix/rest/v2/nodes/NodesWebscriptV2.java | 123 +++----------- .../apix/rest/NodeInfoSerializationTest.java | 29 ---- .../xenit/apix/rest/SearchWebscriptTest.java | 7 +- 20 files changed, 482 insertions(+), 509 deletions(-) create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodeInfoRequest.java delete mode 100644 apix-rest-v1/src/test/java/eu/xenit/apix/rest/NodeInfoSerializationTest.java diff --git a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java index 26a35d41..935704ac 100644 --- a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java @@ -65,7 +65,7 @@ public eu.xenit.apix.data.NodeRef doPostNodes(CreateNodeOptions createNodeOption if (nodeInfo != null) { //deserialization succeeded - return nodeInfo.noderef; + return nodeInfo.getNoderef(); } else { //deserialization failed HttpEntityEnclosingRequestBase req = new HttpPost(url); @@ -104,24 +104,24 @@ protected CreateNodeOptions getCreateNodeOptions(eu.xenit.apix.data.NodeRef pare public void checkCreatedNode(NodeRef newRef, CreateNodeOptions createNodeOptions) { assertTrue(nodeService.exists(newRef)); - assertEquals(createNodeOptions.parent, nodeService.getParentAssociations(newRef).get(0).getTarget().toString()); + assertEquals(createNodeOptions.getParent(), nodeService.getParentAssociations(newRef).get(0).getTarget().toString()); - if (createNodeOptions.type != null) { - assertEquals(createNodeOptions.type, nodeService.getMetadata(newRef).type.toString()); + if (createNodeOptions.getType() != null) { + assertEquals(createNodeOptions.getType(), nodeService.getMetadata(newRef).type.toString()); } - if (createNodeOptions.copyFrom != null) { - assertTrue(nodeService.exists(new NodeRef(createNodeOptions.copyFrom))); + if (createNodeOptions.getCopyFrom() != null) { + assertTrue(nodeService.exists(new NodeRef(createNodeOptions.getCopyFrom()))); } - if (createNodeOptions.properties != null) { - for (Map.Entry property : createNodeOptions.properties.entrySet()) { + if (createNodeOptions.getProperties() != null) { + for (Map.Entry property : createNodeOptions.getProperties().entrySet()) { assertArrayEquals(property.getValue(), nodeService.getMetadata(newRef).properties.get(property.getKey()).toArray()); } } - if (createNodeOptions.aspectsToAdd != null) { - for (QName aspect : createNodeOptions.aspectsToAdd) { + if (createNodeOptions.getAspectsToAdd() != null) { + for (QName aspect : createNodeOptions.getAspectsToAdd()) { assertNotNull(nodeService.getMetadata(newRef).aspects .stream() .filter(testAspect -> testAspect.equals(aspect)) @@ -130,8 +130,8 @@ public void checkCreatedNode(NodeRef newRef, CreateNodeOptions createNodeOptions } } - if (createNodeOptions.aspectsToRemove != null) { - for (QName aspect : createNodeOptions.aspectsToRemove) { + if (createNodeOptions.getAspectsToRemove() != null) { + for (QName aspect : createNodeOptions.getAspectsToRemove()) { assertNull(nodeService.getMetadata(newRef).aspects .stream() .filter(testAspect -> testAspect.equals(aspect)) diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java index f7f86753..e85f2a71 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java @@ -10,13 +10,16 @@ import eu.xenit.apix.permissions.IPermissionService; import eu.xenit.apix.permissions.PermissionValue; import eu.xenit.apix.rest.v1.nodes.NodeInfo; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import eu.xenit.apix.rest.v1.nodes.NodeInfoRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + public class ApixV1Webscript { private static final Logger logger = LoggerFactory.getLogger(ApixV1Webscript.class); @@ -29,24 +32,26 @@ protected NodeRef createNodeRef(String space, String store, String guid) { return new NodeRef(space, store, guid); } - protected List nodeRefToNodeInfo(List nodeRefs, - IFileFolderService fileFolderService, - INodeService nodeService, - IPermissionService permissionService, - boolean retrievePath, - boolean retrieveMetadata, - boolean retrievePermissions, - boolean retrieveAssocs, - boolean retrieveChildAssocs, - boolean retrieveParentAssocs, - boolean retrieveTargetAssocs, - boolean retrieveSourceAssocs + protected List nodeRefToNodeInfo(NodeInfoRequest nodeInfoRequest, + IFileFolderService fileFolderService, + INodeService nodeService, + IPermissionService permissionService ) { List nodeInfoList = new ArrayList<>(); + List nodeRefs = nodeInfoRequest.getNoderefs().stream().map(NodeRef::new).collect(Collectors.toList()); for (NodeRef nodeRef : nodeRefs) { - NodeInfo nodeInfo = nodeRefToNodeInfo(nodeRef, fileFolderService, nodeService, permissionService, - retrievePath, retrieveMetadata, retrievePermissions, retrieveAssocs, retrieveChildAssocs, - retrieveParentAssocs, retrieveTargetAssocs, retrieveSourceAssocs); + NodeInfo nodeInfo = nodeRefToNodeInfo(nodeRef, + fileFolderService, + nodeService, + permissionService, + nodeInfoRequest.getRetrievePath(), + nodeInfoRequest.getRetrieveMetadata(), + nodeInfoRequest.getRetrievePermissions(), + nodeInfoRequest.getRetrieveAssocs(), + nodeInfoRequest.getRetrieveChildAssocs(), + nodeInfoRequest.getRetrieveParentAssocs(), + nodeInfoRequest.getRetrieveTargetAssocs(), + nodeInfoRequest.getRetrieveSourceAssocs()); if (nodeInfo == null) { continue; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkSubResult.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkSubResult.java index 4a21f2e3..f88bdd12 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkSubResult.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkSubResult.java @@ -10,14 +10,14 @@ public class BulkSubResult { private int statusCode; - private JsonNode body; + private Object body; private Map headers; public BulkSubResult() { } - public BulkSubResult(int statusCode, JsonNode body, Map headers) { + public BulkSubResult(int statusCode, Object body, Map headers) { this.statusCode = statusCode; this.body = body; this.headers = headers; @@ -31,7 +31,7 @@ public void setStatusCode(int statusCode) { this.statusCode = statusCode; } - public JsonNode getBody() { + public Object getBody() { return body; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java index 120e3061..fe93596c 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java @@ -1,6 +1,6 @@ package eu.xenit.apix.rest.v1.bulk; -import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.ObjectMapper; import com.gradecak.alfresco.mvc.webscript.DispatcherWebscript; import eu.xenit.apix.rest.v1.ApixV1Webscript; @@ -64,12 +64,11 @@ public ResponseEntity> bulk(@RequestBody final BulkRequest[] bulkHttpServletRequest.getMethod()); - final IntermediateRequest intermediateRequest = new IntermediateRequest(wsReq, bulkHttpServletRequest, - null); + final IntermediateRequest intermediateRequest = new IntermediateRequest(wsReq, bulkHttpServletRequest); - final IntermediateResponse mockRes = new IntermediateResponse(); - final WebScriptServletResponse intermediateResponse = new WebScriptServletResponse(wsReq.getRuntime(), - mockRes); + final IntermediateResponse intermediateResponse = new IntermediateResponse(); + final WebScriptServletResponse webScriptServletResponse = new WebScriptServletResponse(wsReq.getRuntime(), + intermediateResponse); // Each subrequest gets to run in its own transaction context, because even a caught exception can mark a @@ -79,10 +78,10 @@ public ResponseEntity> bulk(@RequestBody final BulkRequest[] .doInTransaction((RetryingTransactionHelper.RetryingTransactionCallback) () -> { try { // Actual execution of called WebScript happens here - dispatcherWebscript.execute(intermediateRequest, intermediateResponse); + dispatcherWebscript.execute(intermediateRequest, webScriptServletResponse); logger.debug("Resp body is '{}'", intermediateResponse.getWriter()); // Convert the response container to json + statuscode + headers - return createBulkResult(mapper, mockRes); + return createBulkResult(mapper, intermediateResponse); } catch (Exception e) { // Catching all exceptions to just print a stacktrace isn't super clean... // But we want the bulk to continue with the other requests even if this one fails. @@ -110,12 +109,16 @@ public ResponseEntity> bulk(@RequestBody final BulkRequest[] private static BulkSubResult createBulkResult(ObjectMapper mapper, IntermediateResponse resp) throws IOException { int status = resp.getStatus(); - JsonNode body; + Object body; String strBody = resp.getContentAsString(); if (strBody == null || strBody.equals("")) { body = mapper.createObjectNode(); } else { - body = mapper.readTree(strBody); + try { + body = mapper.readTree(strBody); + } catch (JsonParseException exception) { + body = strBody; + } } return new BulkSubResult(status, body, resp.getHeaderNames().stream().collect( diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/IntermediateRequest.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/IntermediateRequest.java index 7ec4ab27..e8a32d05 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/IntermediateRequest.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/request/IntermediateRequest.java @@ -1,31 +1,31 @@ package eu.xenit.apix.rest.v1.bulk.request; -import org.springframework.extensions.webscripts.Match; import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest; import javax.servlet.http.HttpServletRequest; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; public class IntermediateRequest extends WebScriptServletRequest { + public static final String MATCH = "apix/"; - - public IntermediateRequest(WebScriptRequest bulkWebScriptRequest, HttpServletRequest request, Match match) { - super(bulkWebScriptRequest.getRuntime(), request, match, null); + public IntermediateRequest(WebScriptRequest bulkWebScriptRequest, HttpServletRequest request) { + super(bulkWebScriptRequest.getRuntime(), request, null, null); } @Override public String getExtensionPath() { String uri = getHttpServletRequest().getRequestURI(); - List uriSplit = new ArrayList<>(Arrays.asList(uri.split("/"))); - uriSplit.remove(0); - uriSplit.remove(0); - uriSplit.remove(0); - uriSplit.remove(0); - return String.join("/", uriSplit); + + if (uri.contains(MATCH)) { + uri = uri.substring(uri.indexOf(MATCH) + MATCH.length()); + } + + if (uri.contains("?")) { + uri = uri.substring(0, uri.indexOf("?")); + } + + return uri; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/AncestorsObject.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/AncestorsObject.java index 8e513f93..2b15a185 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/AncestorsObject.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/AncestorsObject.java @@ -1,6 +1,7 @@ package eu.xenit.apix.rest.v1.nodes; import eu.xenit.apix.data.NodeRef; + import java.util.List; public class AncestorsObject { @@ -8,16 +9,27 @@ public class AncestorsObject { private NodeRef node; private List ancestors; + public AncestorsObject(NodeRef node, List ancestors) { + this.node = node; + this.ancestors = ancestors; + } + + public AncestorsObject() { + } + public NodeRef getNode() { return node; } + public void setNode(NodeRef node) { + this.node = node; + } + public List getAncestors() { return ancestors; } - public AncestorsObject(NodeRef node, List ancestors) { - this.node = node; + public void setAncestors(List ancestors) { this.ancestors = ancestors; } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeAclsOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeAclsOptions.java index 805ac025..6dcb374f 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeAclsOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeAclsOptions.java @@ -2,16 +2,16 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import java.io.IOException; + import java.util.Set; public class ChangeAclsOptions { private boolean inheritFromParent; private Set ownAccessList; - @JsonCreator - public ChangeAclsOptions(@JsonProperty("inheritFromParent") boolean inheritFromParent, - @JsonProperty("ownAccessList") Set ownAccessList) { + + public ChangeAclsOptions( boolean inheritFromParent, + Set ownAccessList) { this.ownAccessList = ownAccessList; this.inheritFromParent = inheritFromParent; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java index 541a9ba4..14d2f3ba 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java @@ -1,17 +1,21 @@ package eu.xenit.apix.rest.v1.nodes; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - /** * Created by Michiel Huygen on 12/05/2016. */ class ChangeParentOptions { - public String parent; + private String parent; + + + public ChangeParentOptions(String parent) { + this.parent = parent; + } + + public ChangeParentOptions() { + } - @JsonCreator - public ChangeParentOptions(@JsonProperty("parent") String parent) { + public void setParent(String parent) { this.parent = parent; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateAssociationOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateAssociationOptions.java index a9c36e15..e96951d5 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateAssociationOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateAssociationOptions.java @@ -7,6 +7,13 @@ * Created by Michiel Huygen on 23/05/2016. */ public class CreateAssociationOptions { + public CreateAssociationOptions(NodeRef target, QName type) { + this.target = target; + this.type = type; + } + + public CreateAssociationOptions() { + } private NodeRef target; private QName type = new QName("{http://www.alfresco.org/model/content/1.0}content"); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java index d2e76fa4..0d7bbce3 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java @@ -1,12 +1,11 @@ package eu.xenit.apix.rest.v1.nodes; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; import eu.xenit.apix.data.QName; +import org.alfresco.model.ContentModel; + import java.util.HashMap; import java.util.Map; -import org.alfresco.model.ContentModel; +import java.util.Objects; /** * Created by Michiel Huygen on 12/05/2016. @@ -14,24 +13,27 @@ public class CreateNodeOptions { public static final QName PROP_NAME_QNAME = new QName(ContentModel.PROP_NAME.toString()); - public String parent; - public String name; - public String type; - public Map properties; - - public QName[] aspectsToAdd; - public QName[] aspectsToRemove; - public String copyFrom; - private ObjectMapper mapper = new ObjectMapper(); - - @JsonCreator - public CreateNodeOptions(@JsonProperty("parent") String parent, - @JsonProperty("name") String name, - @JsonProperty("type") String type, - @JsonProperty("properties") Map properties, - @JsonProperty("aspectsToAdd") QName[] aspectsToAdd, - @JsonProperty("aspectsToRemove") QName[] aspectsToRemove, - @JsonProperty("copyFrom") String copyFrom) { + private String parent; + private String name; + private String type; + private Map properties; + private QName[] aspectsToAdd; + private QName[] aspectsToRemove; + private String copyFrom; + + public CreateNodeOptions() { + this.properties = new HashMap<>(1); + this.aspectsToRemove = new QName[0]; + this.aspectsToAdd = new QName[0]; + } + + public CreateNodeOptions(String parent, + String name, + String type, + Map properties, + QName[] aspectsToAdd, + QName[] aspectsToRemove, + String copyFrom) { this.parent = parent; this.name = name; this.type = type; @@ -39,27 +41,46 @@ public CreateNodeOptions(@JsonProperty("parent") String parent, if (this.properties == null) { this.properties = new HashMap<>(1); } - if ((name != null && !this.properties.containsKey(PROP_NAME_QNAME))) { + if ((name != null && !getProperties().containsKey(PROP_NAME_QNAME))) { this.properties.put(PROP_NAME_QNAME, new String[]{name}); } - if (aspectsToAdd == null) { - this.aspectsToAdd = new QName[0]; - } - else { - this.aspectsToAdd = aspectsToAdd; - } + this.aspectsToAdd = Objects.requireNonNullElseGet(aspectsToAdd, () -> new QName[0]); - if (aspectsToRemove == null) { - this.aspectsToRemove = new QName[0]; - } - else { - this.aspectsToRemove = aspectsToRemove; - } + this.aspectsToRemove = Objects.requireNonNullElseGet(aspectsToRemove, () -> new QName[0]); + + this.copyFrom = copyFrom; + } + + public void setParent(String parent) { + this.parent = parent; + } + + public void setName(String name) { + this.name = name; + } + public void setType(String type) { + this.type = type; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public void setAspectsToAdd(QName[] aspectsToAdd) { + this.aspectsToAdd = aspectsToAdd; + } + + public void setAspectsToRemove(QName[] aspectsToRemove) { + this.aspectsToRemove = aspectsToRemove; + } + + public void setCopyFrom(String copyFrom) { this.copyFrom = copyFrom; } + public String getParent() { return parent; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java index c5cc549b..0b20c763 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java @@ -1,23 +1,21 @@ package eu.xenit.apix.rest.v1.nodes; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - class InheritFromParent { private boolean inheritFromParent; - @JsonCreator - public InheritFromParent(@JsonProperty("inheritFromParent") boolean inheritFromParent) { + public InheritFromParent() { + + } + public InheritFromParent(boolean inheritFromParent) { this.inheritFromParent = inheritFromParent; } public boolean isInheritFromParent() { - return this.inheritFromParent; + return inheritFromParent; } public void setInheritFromParent(boolean inheritFromParent) { this.inheritFromParent = inheritFromParent; } - } \ No newline at end of file diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodeInfo.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodeInfo.java index d67c4503..38d3b366 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodeInfo.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodeInfo.java @@ -12,11 +12,51 @@ */ public class NodeInfo { - public NodeRef noderef; - public NodeMetadata metadata; - public Map permissions; - public NodeAssociations associations; - public NodePath path; + private NodeRef noderef; + private NodeMetadata metadata; + private Map permissions; + private NodeAssociations associations; + private NodePath path; + + public NodeRef getNoderef() { + return noderef; + } + + public void setNoderef(NodeRef noderef) { + this.noderef = noderef; + } + + public NodeMetadata getMetadata() { + return metadata; + } + + public void setMetadata(NodeMetadata metadata) { + this.metadata = metadata; + } + + public Map getPermissions() { + return permissions; + } + + public void setPermissions(Map permissions) { + this.permissions = permissions; + } + + public NodeAssociations getAssociations() { + return associations; + } + + public void setAssociations(NodeAssociations associations) { + this.associations = associations; + } + + public NodePath getPath() { + return path; + } + + public void setPath(NodePath path) { + this.path = path; + } public NodeInfo() { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodeInfoRequest.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodeInfoRequest.java new file mode 100644 index 00000000..992ef582 --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodeInfoRequest.java @@ -0,0 +1,119 @@ +package eu.xenit.apix.rest.v1.nodes; + +import java.util.List; + +public class NodeInfoRequest { + Boolean retrieveMetadata; + Boolean retrievePath; + Boolean retrievePermissions; + Boolean retrieveAssocs; + Boolean retrieveChildAssocs; + Boolean retrieveParentAssocs; + Boolean retrieveTargetAssocs; + Boolean retrieveSourceAssocs; + List noderefs; + + NodeInfoRequest() { + } + + public NodeInfoRequest(Boolean retrieveMetadata, + Boolean retrievePath, + Boolean retrievePermissions, + Boolean retrieveAssocs, + Boolean retrieveChildAssocs, + Boolean retrieveParentAssocs, + Boolean retrieveTargetAssocs, + Boolean retrieveSourceAssocs, + List noderefs) { + this.retrieveMetadata = retrieveMetadata; + this.retrievePath = retrievePath; + this.retrievePermissions = retrievePermissions; + this.retrieveAssocs = retrieveAssocs; + this.retrieveChildAssocs = retrieveChildAssocs; + this.retrieveParentAssocs = retrieveParentAssocs; + this.retrieveTargetAssocs = retrieveTargetAssocs; + this.retrieveSourceAssocs = retrieveSourceAssocs; + this.noderefs = noderefs; + } + + public boolean getRetrieveMetadata() { + return !Boolean.FALSE.equals(retrieveMetadata); + + } + + public void setRetrieveMetadata(Boolean retrieveMetadata) { + this.retrieveMetadata = retrieveMetadata; + } + + public boolean getRetrievePath() { + return !Boolean.FALSE.equals(retrievePath); + } + + public void setRetrievePath(Boolean retrievePath) { + this.retrievePath = retrievePath; + } + + public boolean getRetrievePermissions() { + return !Boolean.FALSE.equals(retrievePermissions); + + } + + public void setRetrievePermissions(Boolean retrievePermissions) { + this.retrievePermissions = retrievePermissions; + } + + public boolean getRetrieveAssocs() { + return !Boolean.FALSE.equals(retrieveAssocs); + + } + + public void setRetrieveAssocs(Boolean retrieveAssocs) { + this.retrieveAssocs = retrieveAssocs; + } + + public boolean getRetrieveChildAssocs() { + return !Boolean.FALSE.equals(retrieveChildAssocs); + + } + + public void setRetrieveChildAssocs(Boolean retrieveChildAssocs) { + this.retrieveChildAssocs = retrieveChildAssocs; + } + + public boolean getRetrieveParentAssocs() { + + return !Boolean.FALSE.equals(retrieveParentAssocs); + + } + + public void setRetrieveParentAssocs(Boolean retrieveParentAssocs) { + this.retrieveParentAssocs = retrieveParentAssocs; + + } + + public boolean getRetrieveTargetAssocs() { + return !Boolean.FALSE.equals(retrieveTargetAssocs); + + } + + public void setRetrieveTargetAssocs(Boolean retrieveTargetAssocs) { + this.retrieveTargetAssocs = retrieveTargetAssocs; + } + + public boolean getRetrieveSourceAssocs() { + return !Boolean.FALSE.equals(retrieveSourceAssocs); + + } + + public void setRetrieveSourceAssocs(Boolean retrieveSourceAssocs) { + this.retrieveSourceAssocs = retrieveSourceAssocs; + } + + public List getNoderefs() { + return noderefs; + } + + public void setNoderefs(List noderefs) { + this.noderefs = noderefs; + } +} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java index b13a378b..166a1c26 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java @@ -21,12 +21,6 @@ import eu.xenit.apix.permissions.PermissionValue; import eu.xenit.apix.rest.v1.ApixV1Webscript; import eu.xenit.apix.rest.v1.nodes.ChangeAclsOptions.Access; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.transaction.RetryingTransactionHelper; @@ -34,9 +28,6 @@ import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.security.PermissionService; import org.apache.http.HttpStatus; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.InputStreamResource; @@ -53,6 +44,12 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + @AlfrescoTransaction @RestController("eu.xenit.apix.rest.v1.NodesWebscript") @@ -82,11 +79,11 @@ public NodesWebscript1(INodeService nodeService, IPermissionService permissionSe @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/metadata") public ResponseEntity setMetadata(@PathVariable final String space, @PathVariable final String store, - @PathVariable final String guid, @RequestBody final MetadataChanges changes) { + @PathVariable final String guid, @RequestBody final MetadataChanges changes) { NodeRef nodeRef = createNodeRef(space, store, guid); NodeMetadata nodeMetadata = nodeService.setMetadata(nodeRef, changes); if (nodeMetadata == null) { - ResponseEntity.notFound(); + ResponseEntity.notFound(); } return writeJsonResponse(nodeMetadata); } @@ -233,7 +230,7 @@ public ResponseEntity getAcls(@PathVariable String space, @PathV @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/acl/inheritFromParent") public void setInheritParentPermissions(@PathVariable String space, @PathVariable String store, - @PathVariable String guid, @RequestBody final InheritFromParent inherit) { + @PathVariable String guid, @RequestBody final InheritFromParent inherit) { this.permissionService.setInheritParentPermissions( this.createNodeRef(space, store, guid), inherit.isInheritFromParent() ); @@ -291,7 +288,7 @@ public ResponseEntity getAllInfoOfNode(@PathVariable String space, @Path .body(String.format("Insufficient permissions for node %s://%s/%s", space, store, guid)); } catch (InvalidNodeRefException invalidNodeRefException) { logger.debug("Failed to get node info, node does not exist: {}://{}/{}", space, store, guid, - invalidNodeRefException); + invalidNodeRefException); return ResponseEntity .status(HttpStatus.SC_NOT_FOUND) .body("Failed to get node info, node does not exist."); @@ -299,74 +296,12 @@ public ResponseEntity getAllInfoOfNode(@PathVariable String space, @Path } @PostMapping(value = "/v1/nodes/nodeInfo") - public ResponseEntity getAllInfoOfNodes(@RequestBody final String requestString) { - logger.debug("request content: {}", requestString); - JSONObject jsonObject = new JSONObject(requestString); - logger.debug("json: {}", jsonObject); - - boolean retrieveMetadata = true; - boolean retrievePath = true; - boolean retrievePermissions = true; - boolean retrieveAssocs = true; - boolean retrieveChildAssocs = true; - boolean retrieveParentAssocs = true; - boolean retrieveTargetAssocs = true; - boolean retrieveSourceAssocs = true; - - List nodeRefs = new ArrayList<>(); - try { - if (jsonObject.has("retrieveMetadata")) { - retrieveMetadata = jsonObject.getBoolean("retrieveMetadata"); - } - if (jsonObject.has("retrievePath")) { - retrievePath = jsonObject.getBoolean("retrievePath"); - } - if (jsonObject.has("retrievePermissions")) { - retrievePermissions = jsonObject.getBoolean("retrievePermissions"); - } - if (jsonObject.has("retrieveAssocs")) { - retrieveAssocs = jsonObject.getBoolean("retrieveAssocs"); - } - if (jsonObject.has("retrieveChildAssocs")) { - retrieveChildAssocs = jsonObject.getBoolean("retrieveChildAssocs"); - } - if (jsonObject.has("retrieveParentAssocs")) { - retrieveParentAssocs = jsonObject.getBoolean("retrieveParentAssocs"); - } - if (jsonObject.has("retrieveTargetAssocs")) { - retrieveTargetAssocs = jsonObject.getBoolean("retrieveTargetAssocs"); - } - if (jsonObject.has("retrieveSourceAssocs")) { - retrieveSourceAssocs = jsonObject.getBoolean("retrieveSourceAssocs"); - } - - JSONArray nodeRefsJsonArray = jsonObject.getJSONArray("noderefs"); - int nodeRefsJsonArrayLength = nodeRefsJsonArray.length(); - logger.debug("nodeRefsJsonArrayLength: {}", nodeRefsJsonArrayLength); - for (int i = 0; i < nodeRefsJsonArrayLength; i++) { - String nodeRefString = (String) nodeRefsJsonArray.get(i); - logger.debug("nodeRefString: {}", nodeRefString); - NodeRef nodeRef = new NodeRef(nodeRefString); - nodeRefs.add(nodeRef); - } - } catch (JSONException e) { - logger.error("Error deserializing json body", e); - return ResponseEntity.badRequest().build(); - } - - List nodeInfoList = this.nodeRefToNodeInfo(nodeRefs, + public ResponseEntity getAllInfoOfNodes(@RequestBody final NodeInfoRequest nodeInfoRequest) { + List nodeInfoList = this.nodeRefToNodeInfo(nodeInfoRequest, this.fileFolderService, this.nodeService, - this.permissionService, - retrievePath, - retrieveMetadata, - retrievePermissions, - retrieveAssocs, - retrieveChildAssocs, - retrieveParentAssocs, - retrieveTargetAssocs, - retrieveSourceAssocs); - + this.permissionService + ); return writeJsonResponse(nodeInfoList); } @@ -387,7 +322,7 @@ public ResponseEntity retrieveAncestors(@PathVariable String space, @Pat } catch (InvalidNodeRefException ex) { logger.error("noderef does not exist", ex); return ResponseEntity.status(HttpStatus.SC_NOT_FOUND) - .body(ex.getMessage()); + .body(ex.getMessage()); } catch (AccessDeniedException ex) { logger.error("access denied on noderef", ex); return ResponseEntity.status(HttpStatus.SC_FORBIDDEN) @@ -400,7 +335,7 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions try { Object resultObject = serviceRegistry.getRetryingTransactionHelper() .doInTransaction(() -> { - NodeRef parent = new NodeRef(createNodeOptions.parent); + NodeRef parent = new NodeRef(createNodeOptions.getParent()); if (!nodeService.exists(parent)) { return writeNotFoundResponse(parent); @@ -408,12 +343,12 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions NodeRef nodeRef; NodeRef copyFrom = null; - if (createNodeOptions.copyFrom == null) { + if (createNodeOptions.getCopyFrom() == null) { nodeRef = nodeService - .createNode(parent, createNodeOptions.name, - new QName(createNodeOptions.type)); + .createNode(parent, createNodeOptions.getName(), + new QName(createNodeOptions.getType())); } else { - copyFrom = new NodeRef(createNodeOptions.copyFrom); + copyFrom = new NodeRef(createNodeOptions.getCopyFrom()); if (!nodeService.exists(copyFrom)) { return writeNotFoundResponse(copyFrom); } @@ -432,9 +367,9 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions } metadataChanges = new MetadataChanges(type, - createNodeOptions.aspectsToAdd, - createNodeOptions.aspectsToRemove, - createNodeOptions.properties); + createNodeOptions.getAspectsToAdd(), + createNodeOptions.getAspectsToRemove(), + createNodeOptions.getProperties()); nodeService.setMetadata(nodeRef, metadataChanges); return nodeRef; @@ -451,7 +386,7 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions return writeJsonResponse(nodeInfo); } catch (org.alfresco.service.cmr.model.FileExistsException fileExistsException) { throw new FileExistsException( - new NodeRef(createNodeOptions.copyFrom), + new NodeRef(createNodeOptions.getCopyFrom()), new NodeRef(fileExistsException.getParentNodeRef().toString()), fileExistsException.getName()); } @@ -459,14 +394,14 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions @PutMapping(value = "/v1/nodes/{space}/{store}/{guid}/parent") public ResponseEntity setParent(@PathVariable final String space, @PathVariable final String store, - @PathVariable final String guid, @RequestBody ChangeParentOptions location) { + @PathVariable final String guid, @RequestBody ChangeParentOptions location) { NodeRef nodeToMove = createNodeRef(space, store, guid); try { return ResponseEntity.ok( - nodeService.moveNode( - nodeToMove, - new NodeRef(location.getParent()) - ) + nodeService.moveNode( + nodeToMove, + new NodeRef(location.getParent()) + ) ); } catch (org.alfresco.service.cmr.model.FileExistsException fileExistsException) { throw new FileExistsException( @@ -478,8 +413,8 @@ public ResponseEntity setParent(@PathVariable final String space, @Path @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/comments") public ResponseEntity getComments(@PathVariable String space, @PathVariable String store, - @PathVariable String guid, @RequestParam(defaultValue = "0") int skipcount, - @RequestParam(defaultValue = "10") int pagesize) { + @PathVariable String guid, @RequestParam(defaultValue = "0") int skipcount, + @RequestParam(defaultValue = "10") int pagesize) { final NodeRef target = this.createNodeRef(space, store, guid); if (!nodeService.exists(target)) { return writeNotFoundResponse(target); @@ -495,7 +430,7 @@ public ResponseEntity getComments(@PathVariable String space, @PathVariable S @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/comments") public ResponseEntity addComment(@PathVariable String space, @PathVariable String store, - @PathVariable String guid, @RequestBody final Comment newComment) { + @PathVariable String guid, @RequestBody final Comment newComment) { final NodeRef target = this.createNodeRef(space, store, guid); if (!nodeService.exists(target)) { return writeNotFoundResponse(target); @@ -606,7 +541,7 @@ public ResponseEntity uploadNode( // Both setting metadata and extracting metadata are optional. // They can happen (or not) independently from each other. type = type == null ? ContentModel.TYPE_CONTENT.toString() : type; - extractMetadata = extractMetadata != null && extractMetadata; + extractMetadata = Boolean.TRUE.equals(extractMetadata); if (file == null) { throw new IllegalArgumentException("Content must be supplied as a multipart 'file' field"); @@ -636,10 +571,10 @@ public ResponseEntity uploadNode( } public NodeRef createNodeForUpload(String finalParent, - MultipartFile file, - String finalType, - MetadataChanges finalMetadata, - Boolean finalExtractMetadata) throws IOException { + MultipartFile file, + String finalType, + MetadataChanges finalMetadata, + Boolean finalExtractMetadata) throws IOException { NodeRef newNode = nodeService .createNode(new NodeRef(finalParent), file.getOriginalFilename(), new QName(finalType)); @@ -661,7 +596,7 @@ public NodeRef createNodeForUpload(String finalParent, } @ExceptionHandler(AccessDeniedException.class) - private ResponseEntity writeNotAuthorizedResponse(AccessDeniedException ex) { + private ResponseEntity writeNotAuthorizedResponse(AccessDeniedException ex) { logger.debug("Not Authorized", ex); return ResponseEntity .status(HttpStatus.SC_FORBIDDEN) @@ -669,7 +604,7 @@ private ResponseEntity writeNotAuthorizedResponse(AccessDeniedException } @ExceptionHandler(FileExistsException.class) - private ResponseEntity writeFileExistsResponse(FileExistsException fileExistsException) { + private ResponseEntity writeFileExistsResponse(FileExistsException fileExistsException) { String message = fileExistsException.toString(); logger.debug(message, fileExistsException); return ResponseEntity @@ -677,7 +612,7 @@ private ResponseEntity writeFileExistsResponse(FileExistsException fileE .body(message); } - private ResponseEntity writeNotFoundResponse(NodeRef requestedNode) { + private ResponseEntity writeNotFoundResponse(NodeRef requestedNode) { String message = String.format("Node Not Found: %s", requestedNode); logger.debug(message); return ResponseEntity diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/Charsets.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/Charsets.java index a34807d0..c40c02ab 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/Charsets.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/Charsets.java @@ -20,67 +20,6 @@ import java.nio.charset.UnsupportedCharsetException; public class Charsets { - // - // This class should only contain Charset instances for required encodings. This guarantees that it will load - // correctly and without delay on all Java platforms. - // - - /** - * CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1. - *

- * Every implementation of the Java platform is required to support this character encoding. - * - * @see Standard charsets - */ - public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); - /** - *

- * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set. - * - *

- * Every implementation of the Java platform is required to support this character encoding. - * - * @see Standard charsets - */ - public static final Charset US_ASCII = Charset.forName("US-ASCII"); - /** - *

- * Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark - * (either order accepted on input, big-endian used on output) - *

- * Every implementation of the Java platform is required to support this character encoding. - * - * @see Standard charsets - */ - public static final Charset UTF_16 = Charset.forName("UTF-16"); - /** - *

- * Sixteen-bit Unicode Transformation Format, big-endian byte order. - *

- * Every implementation of the Java platform is required to support this character encoding. - * - * @see Standard charsets - */ - public static final Charset UTF_16BE = Charset.forName("UTF-16BE"); - /** - *

- * Sixteen-bit Unicode Transformation Format, little-endian byte order. - *

- * Every implementation of the Java platform is required to support this character encoding. - * - * @see Standard charsets - */ - public static final Charset UTF_16LE = Charset.forName("UTF-16LE"); - /** - *

- * Eight-bit Unicode Transformation Format. - *

- * Every implementation of the Java platform is required to support this character encoding. - * - * @see Standard charsets - */ - public static final Charset UTF_8 = Charset.forName("UTF-8"); - /** * Returns the given Charset or the default Charset if the given Charset is null. * diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/ReversedLinesFileReader.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/ReversedLinesFileReader.java index 8a51e3d2..d498a7d6 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/ReversedLinesFileReader.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/ReversedLinesFileReader.java @@ -23,6 +23,7 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; +import java.nio.charset.StandardCharsets; import java.nio.charset.UnsupportedCharsetException; @@ -63,10 +64,10 @@ public ReversedLinesFileReader(final File file) throws IOException { /** * Creates a ReversedLinesFileReader with the given block size and encoding. * - * @param file the file to be read + * @param file the file to be read * @param blockSize size of the internal buffer (for ideal performance this should match with the block size of the - * underlying file system). - * @param encoding the encoding of the file + * underlying file system). + * @param encoding the encoding of the file * @throws IOException if an I/O error occurs * @since 2.3 */ @@ -94,7 +95,7 @@ public ReversedLinesFileReader(final File file, final int blockSize, final Chars if (maxBytesPerChar == 1f) { // all one byte encodings are no problem byteDecrement = 1; - } else if (charset == Charset.forName("UTF-8")) { + } else if (charset.equals(StandardCharsets.UTF_8)) { // UTF-8 works fine out of the box, for multibyte sequences a second UTF-8 byte can never be a newline byte // http://en.wikipedia.org/wiki/UTF-8 byteDecrement = 1; @@ -102,11 +103,11 @@ public ReversedLinesFileReader(final File file, final int blockSize, final Chars // Same as for UTF-8 // http://www.herongyang.com/Unicode/JIS-Shift-JIS-Encoding.html byteDecrement = 1; - } else if (charset == Charset.forName("UTF-16BE") || charset == Charset.forName("UTF-16LE")) { + } else if (charset.equals(StandardCharsets.UTF_16BE) || charset.equals(StandardCharsets.UTF_16LE)) { // UTF-16 new line sequences are not allowed as second tuple of four byte sequences, // however byte order has to be specified byteDecrement = 2; - } else if (charset == Charset.forName("UTF-16")) { + } else if (charset.equals(StandardCharsets.UTF_16)) { throw new UnsupportedEncodingException( "For UTF-16, you need to specify the byte order (use UTF-16BE or UTF-16LE)"); } else { @@ -122,13 +123,13 @@ public ReversedLinesFileReader(final File file, final int blockSize, final Chars /** * Creates a ReversedLinesFileReader with the given block size and encoding. * - * @param file the file to be read + * @param file the file to be read * @param blockSize size of the internal buffer (for ideal performance this should match with the block size of the - * underlying file system). - * @param encoding the encoding of the file - * @throws IOException if an I/O error occurs + * underlying file system). + * @param encoding the encoding of the file + * @throws IOException if an I/O error occurs * @throws UnsupportedCharsetException thrown instead of {@link UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. + * encoding is not supported. */ public ReversedLinesFileReader(final File file, final int blockSize, final String encoding) throws IOException { this(file, blockSize, Charsets.toCharset(encoding)); @@ -184,8 +185,8 @@ private class FilePart { /** * ctor * - * @param no the part number - * @param length its length + * @param no the part number + * @param length its length * @param leftOverOfLastFilePart remainder * @throws IOException if there is a problem reading the file */ @@ -315,7 +316,7 @@ private void createLeftOver() { * Finds the new-line sequence and return its length. * * @param data buffer to scan - * @param i start offset in buffer + * @param i start offset in buffer * @return length of newline sequence or 0 if none found */ private int getNewLineMatchByteCount(byte[] data, int i) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/ApixV2Webscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/ApixV2Webscript.java index 029069f9..daabacd5 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/ApixV2Webscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/ApixV2Webscript.java @@ -2,6 +2,7 @@ import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.filefolder.IFileFolderService; +import eu.xenit.apix.filefolder.NodePath; import eu.xenit.apix.node.ChildParentAssociation; import eu.xenit.apix.node.INodeService; import eu.xenit.apix.node.NodeAssociation; @@ -11,12 +12,13 @@ import eu.xenit.apix.permissions.PermissionValue; import eu.xenit.apix.rest.v1.ApixV1Webscript; import eu.xenit.apix.rest.v1.nodes.NodeInfo; +import eu.xenit.apix.rest.v1.nodes.NodeInfoRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * Created by jasper on 16/02/17. @@ -25,93 +27,91 @@ public class ApixV2Webscript extends ApixV1Webscript { private static final Logger logger = LoggerFactory.getLogger(ApixV2Webscript.class); - protected List nodeRefToNodeInfo(List nodeRefs, IFileFolderService fileFolderService, - INodeService nodeService, IPermissionService permissionService) { - List nodeInfoList = new ArrayList<>(); - for (NodeRef nodeRef : nodeRefs) { - eu.xenit.apix.filefolder.NodePath path = fileFolderService.getPath(nodeRef); - NodeMetadata nodeMetadata = nodeService.getMetadata(nodeRef); - Map permissions = permissionService.getPermissionsFast(nodeRef); - NodeAssociations associations = nodeService.getAssociations(nodeRef); - NodeInfo nodeInfo = new NodeInfo(nodeRef, nodeMetadata, permissions, associations, path); - nodeInfoList.add(nodeInfo); - } - - return nodeInfoList; + protected List nodeRefToNodeInfo(NodeInfoRequest nodeInfoRequest, IFileFolderService fileFolderService, + INodeService nodeService, IPermissionService permissionService) { + List nodeRefs = nodeInfoRequest.getNoderefs().stream().map(NodeRef::new).collect(Collectors.toList()); + + return nodeRefs.stream().filter(nodeRef -> { + boolean hasPermission = permissionService.hasPermission(nodeRef, IPermissionService.READ); + if (!hasPermission) { + logger.warn("Excluding node {} from results due to insufficient permissions", nodeRef); + } + return hasPermission; + + }) + .filter(nodeRef -> { + boolean exists = nodeService.exists(nodeRef); + if (!exists) { + logger.debug("Excluding node {} from results because it does not exist", nodeRef); + } + return exists; + + }).map(nodeRef -> { + logger.debug("######################################################"); + logger.debug("start new NodeInfo"); + NodeInfo nodeInfo = new NodeInfo(nodeRef, + getNodeMetadata(nodeInfoRequest, nodeService, nodeRef), + getNodePermissions(nodeInfoRequest, permissionService, nodeRef), + getNodeAssociations(nodeInfoRequest, nodeService, nodeRef) + , getNodePath(nodeInfoRequest, fileFolderService, nodeRef)); + logger.debug("end new NodeInfo"); + return nodeInfo; + }).collect(Collectors.toList()); } - protected List nodeRefToNodeInfo(List nodeRefs, IFileFolderService fileFolderService, - INodeService nodeService, IPermissionService permissionService, - boolean retrievePath, boolean retrieveMetadata, - boolean retrievePermissions, boolean retrieveAssocs, - boolean retrieveChildAssocs, boolean retrieveParentAssocs, - boolean retrieveTargetAssocs, boolean retrieveSourceAssocs) { - List nodeInfoList = new ArrayList<>(); - for (NodeRef nodeRef : nodeRefs) { - - if (!permissionService.hasPermission(nodeRef, IPermissionService.READ)) { - logger.warn("Excluding node {} from results due to insufficient permissions", nodeRef); - continue; - } + private Map getNodePermissions(NodeInfoRequest nodeInfoRequest, IPermissionService permissionService, NodeRef nodeRef) { + logger.debug("start getPermissions"); + Map permissions = null; + if (nodeInfoRequest.getRetrievePermissions()) { + permissions = permissionService.getPermissionsFast(nodeRef); + } + logger.debug("end getPermissions"); + return permissions; + } - if (!nodeService.exists(nodeRef)) { - logger.debug("Excluding node {} from results because it does not exist", nodeRef); - continue; - } + private NodeMetadata getNodeMetadata(NodeInfoRequest nodeInfoRequest, INodeService nodeService, NodeRef nodeRef) { + logger.debug("start getMetadata"); + NodeMetadata nodeMetadata = null; + if (nodeInfoRequest.getRetrieveMetadata()) { + nodeMetadata = nodeService.getMetadata(nodeRef); + } + logger.debug("end getMetadata"); + return nodeMetadata; + } - logger.debug("######################################################"); + private NodePath getNodePath(NodeInfoRequest nodeInfoRequest, IFileFolderService fileFolderService, NodeRef nodeRef) { + logger.debug("start getPath"); + NodePath path = null; + if (nodeInfoRequest.getRetrievePath()) { + path = fileFolderService.getPath(nodeRef); + } + logger.debug("end getPath"); + return path; + } - logger.debug("start getPath"); - eu.xenit.apix.filefolder.NodePath path = null; - if (retrievePath) { - path = fileFolderService.getPath(nodeRef); + private NodeAssociations getNodeAssociations(NodeInfoRequest nodeInfoRequest, INodeService nodeService, NodeRef nodeRef) { + logger.debug("start getAssociations"); + NodeAssociations associations = null; + if (nodeInfoRequest.getRetrieveAssocs()) { + List childAssocs = null; + if (nodeInfoRequest.getRetrieveChildAssocs()) { + childAssocs = nodeService.getChildAssociations(nodeRef); } - logger.debug("end getPath"); - - logger.debug("start getMetadata"); - NodeMetadata nodeMetadata = null; - if (retrieveMetadata) { - nodeMetadata = nodeService.getMetadata(nodeRef); + List parentAssociations = null; + if (nodeInfoRequest.getRetrieveParentAssocs()) { + parentAssociations = nodeService.getParentAssociations(nodeRef); } - logger.debug("end getMetadata"); - - logger.debug("start getPermissions"); - Map permissions = null; - if (retrievePermissions) { - permissions = permissionService.getPermissionsFast(nodeRef); + List targetAssociations = null; + if (nodeInfoRequest.getRetrieveTargetAssocs()) { + targetAssociations = nodeService.getTargetAssociations(nodeRef); } - logger.debug("end getPermissions"); - - logger.debug("start getAssociations"); - NodeAssociations associations = null; - if (retrieveAssocs) { - List childAssocs = null; - if (retrieveChildAssocs) { - childAssocs = nodeService.getChildAssociations(nodeRef); - } - List parentAssociations = null; - if (retrieveParentAssocs) { - parentAssociations = nodeService.getParentAssociations(nodeRef); - } - List targetAssociations = null; - if (retrieveTargetAssocs) { - targetAssociations = nodeService.getTargetAssociations(nodeRef); - } - List sourceAssociations = null; - if (retrieveSourceAssocs) { - targetAssociations = nodeService.getSourceAssociations(nodeRef); - } - associations = new NodeAssociations(childAssocs, parentAssociations, targetAssociations, sourceAssociations); + List sourceAssociations = null; + if (nodeInfoRequest.getRetrieveSourceAssocs()) { + sourceAssociations = nodeService.getSourceAssociations(nodeRef); } - logger.debug("end getAssociations"); - - logger.debug("start new NodeInfo"); - NodeInfo nodeInfo = new NodeInfo(nodeRef, nodeMetadata, permissions, associations, path); - logger.debug("end new NodeInfo"); - - nodeInfoList.add(nodeInfo); + associations = new NodeAssociations(childAssocs, parentAssociations, targetAssociations, sourceAssociations); } - - return nodeInfoList; + logger.debug("end getAssociations"); + return associations; } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java index eec117b7..8740e68a 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java @@ -10,16 +10,11 @@ import eu.xenit.apix.permissions.PermissionValue; import eu.xenit.apix.rest.v1.nodes.CreateNodeOptions; import eu.xenit.apix.rest.v1.nodes.NodeInfo; +import eu.xenit.apix.rest.v1.nodes.NodeInfoRequest; import eu.xenit.apix.rest.v2.ApixV2Webscript; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; import org.alfresco.service.ServiceRegistry; import org.apache.http.HttpStatus; -import org.json.JSONArray; import org.json.JSONException; -import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; @@ -29,6 +24,10 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + @AlfrescoAuthentication @RestController("eu.xenit.apix.rest.v2.NodesWebscript") public class NodesWebscriptV2 extends ApixV2Webscript { @@ -64,94 +63,12 @@ public ResponseEntity getAllInfo(@PathVariable String space, } @PostMapping(value = "/v2/nodes/nodeInfo") - public ResponseEntity getAllInfos(@RequestBody final String requestString) throws JSONException { - logger.debug("entered getAllInfo method"); - if (requestString == null || requestString.isEmpty()) { - String message = String - .format("Malfromed body: request string could not be parsed to jsonObject: %s", requestString); - logger.debug(message); - return ResponseEntity.status(org.springframework.http.HttpStatus.BAD_REQUEST) - .body(message); - } - logger.debug("request content: {}", requestString); - JSONObject jsonObject = new JSONObject(requestString); - logger.debug("json: {}", jsonObject); - - boolean retrieveMetadata = true; - boolean retrievePath = true; - boolean retrievePermissions = true; - boolean retrieveAssocs = true; - boolean retrieveChildAssocs = true; - boolean retrieveParentAssocs = true; - boolean retrieveTargetAssocs = true; - boolean retrieveSourceAssocs = true; - - List nodeRefs = new ArrayList(); - try { - if (jsonObject.has("retrieveMetadata")) { - retrieveMetadata = jsonObject.getBoolean("retrieveMetadata"); - } - if (jsonObject.has("retrievePath")) { - retrievePath = jsonObject.getBoolean("retrievePath"); - } - if (jsonObject.has("retrievePermissions")) { - retrievePermissions = jsonObject.getBoolean("retrievePermissions"); - } - if (jsonObject.has("retrieveAssocs")) { - retrieveAssocs = jsonObject.getBoolean("retrieveAssocs"); - } - if (jsonObject.has("retrieveChildAssocs")) { - retrieveChildAssocs = jsonObject.getBoolean("retrieveChildAssocs"); - } - if (jsonObject.has("retrieveParentAssocs")) { - retrieveParentAssocs = jsonObject.getBoolean("retrieveParentAssocs"); - } - if (jsonObject.has("retrieveTargetAssocs")) { - retrieveTargetAssocs = jsonObject.getBoolean("retrieveTargetAssocs"); - } - if (jsonObject.has("retrieveSourceAssocs")) { - retrieveSourceAssocs = jsonObject.getBoolean("retrieveSourceAssocs"); - } - - JSONArray nodeRefsJsonArray = jsonObject.getJSONArray("noderefs"); - if (nodeRefsJsonArray == null) { - String message = String.format("Could not retrieve target noderefs from body: %s", jsonObject); - return ResponseEntity.status(org.springframework.http.HttpStatus.BAD_REQUEST) - .body(message); - } - int nodeRefsJsonArrayLength = nodeRefsJsonArray.length(); - logger.debug("nodeRefsJsonArrayLength: {}", nodeRefsJsonArrayLength); - for (int i = 0; i < nodeRefsJsonArrayLength; i++) { - String nodeRefString = (String) nodeRefsJsonArray.get(i); - logger.debug("nodeRefString: {}", nodeRefString); - NodeRef nodeRef = new NodeRef(nodeRefString); - nodeRefs.add(nodeRef); - } - } catch (JSONException e) { - logger.error("Error deserializing json body", e); - String message = String.format("Malformed json body %s", jsonObject); - return ResponseEntity.status(org.springframework.http.HttpStatus.BAD_REQUEST) - .body(message); - } - - logger.debug("done parsing request data"); - logger.debug("start nodeRefToNodeInfo"); + public ResponseEntity> getAllInfos(@RequestBody final NodeInfoRequest nodeInfoRequest) throws JSONException { List nodeInfoList = this.nodeRefToNodeInfo( - nodeRefs, + nodeInfoRequest, this.fileFolderService, this.nodeService, - this.permissionService, - retrievePath, - retrieveMetadata, - retrievePermissions, - retrieveAssocs, - retrieveChildAssocs, - retrieveParentAssocs, - retrieveTargetAssocs, - retrieveSourceAssocs); - logger.debug("end nodeRefToNodeInfo"); - - logger.debug("writeJsonResponse"); + this.permissionService); return writeJsonResponse(nodeInfoList); } @@ -161,7 +78,7 @@ public ResponseEntity> getPermissions(@PathVariable @PathVariable String guid) { NodeRef nodeRef = this.createNodeRef(space, store, guid); return writeJsonResponse( - this.permissionService.getPermissionsFast(nodeRef) + this.permissionService.getPermissionsFast(nodeRef) ); } @@ -171,7 +88,7 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions createN final AtomicInteger errorCode = new AtomicInteger(); Object resultObject = serviceRegistry.getRetryingTransactionHelper() .doInTransaction(() -> { - NodeRef parent = new NodeRef(createNodeOptions.parent); + NodeRef parent = new NodeRef(createNodeOptions.getParent()); if (!nodeService.exists(parent)) { errorCode.addAndGet(HttpStatus.SC_NOT_FOUND); @@ -181,12 +98,12 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions createN NodeRef nodeRef; NodeRef copyFrom = null; - if (createNodeOptions.copyFrom == null) { + if (createNodeOptions.getCopyFrom() == null) { nodeRef = nodeService - .createNode(parent, createNodeOptions.name, - new QName(createNodeOptions.type)); + .createNode(parent, createNodeOptions.getName(), + new QName(createNodeOptions.getType())); } else { - copyFrom = new NodeRef(createNodeOptions.copyFrom); + copyFrom = new NodeRef(createNodeOptions.getCopyFrom()); if (!nodeService.exists(copyFrom)) { errorCode.addAndGet(HttpStatus.SC_NOT_FOUND); errorMessage.append("CopyFrom does not exist"); @@ -197,25 +114,25 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions createN MetadataChanges metadataChanges; QName type; - if (createNodeOptions.type != null) { - type = new QName(createNodeOptions.type); - } else if ( createNodeOptions.type == null && createNodeOptions.copyFrom != null ) { + if (createNodeOptions.getType() != null) { + type = new QName(createNodeOptions.getType()); + } else if (createNodeOptions.getCopyFrom() != null) { type = nodeService.getMetadata(copyFrom).type; } else { errorCode.addAndGet(HttpStatus.SC_BAD_REQUEST); errorMessage.append( - "Please provide parameter \"type\" when creating a new node" + "Please provide parameter \"type\" when creating a new node" ); return null; } metadataChanges = new MetadataChanges(type, null, null, - createNodeOptions.properties); + createNodeOptions.getProperties()); nodeService.setMetadata(nodeRef, metadataChanges); return nodeRef; }, false, true); - if(resultObject == null) { + if (resultObject == null) { return ResponseEntity.status(errorCode.get()) .body(errorMessage.toString()); } diff --git a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/NodeInfoSerializationTest.java b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/NodeInfoSerializationTest.java deleted file mode 100644 index 1f24dd8b..00000000 --- a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/NodeInfoSerializationTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package eu.xenit.apix.rest; - -import com.fasterxml.jackson.databind.ObjectMapper; -import eu.xenit.apix.data.NodeRef; -import eu.xenit.apix.data.QName; -import eu.xenit.apix.node.ChildParentAssociation; -import eu.xenit.apix.node.NodeAssociations; -import eu.xenit.apix.rest.v1.nodes.NodeInfo; -import java.io.IOException; -import java.util.ArrayList; -import org.junit.Test; - -/** - * Created by Michiel Huygen on 19/05/2016. - */ -public class NodeInfoSerializationTest { - - @Test - - public void TestDeserializeNodeInfoJson() throws IOException { - NodeInfo nodeinfo = new NodeInfo(); - nodeinfo.associations = new NodeAssociations(); - nodeinfo.associations.setParents(new ArrayList()); - nodeinfo.associations.getParents().add(new ChildParentAssociation(new NodeRef("workspace://SpacesStore/7987"), - new NodeRef("workspace://SpacesStore/7987"), new QName("hello"), false)); - - new ObjectMapper().readValue(new ObjectMapper().writeValueAsString(nodeinfo), NodeInfo.class); - } -} diff --git a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/SearchWebscriptTest.java b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/SearchWebscriptTest.java index 5650188f..609df2e7 100644 --- a/apix-rest-v1/src/test/java/eu/xenit/apix/rest/SearchWebscriptTest.java +++ b/apix-rest-v1/src/test/java/eu/xenit/apix/rest/SearchWebscriptTest.java @@ -3,12 +3,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import eu.xenit.apix.search.SearchQuery; import eu.xenit.apix.search.json.SearchNodeJsonParser; +import org.junit.Assert; +import org.junit.Test; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; -import org.junit.Assert; -import org.junit.Test; /** * Created by jasper on 04/04/17. @@ -22,6 +23,6 @@ public void Test() throws IOException { String jsonInput = "{\"query\":{\"property\":{\"name\":\"cm:name\",\"value\":\"Company Home\"}},\"paging\":{\"limit\":1,\"skip\":0},\"facets\":{\"enabled\":false}}"; InputStream stream = new ByteArrayInputStream(jsonInput.getBytes(StandardCharsets.UTF_8)); SearchQuery q = m.readValue(stream, SearchQuery.class); - Assert.assertTrue(q != null); + Assert.assertNotNull(q); } } From f63f8e3f8700cd0690a585cb28542c79563ad57c Mon Sep 17 00:00:00 2001 From: Hechmi Dammak Date: Mon, 24 Apr 2023 08:46:28 +0100 Subject: [PATCH 42/90] ALFREDAPI-518 fix ci logic --- .github/workflows/ci.yml | 79 ++++++++++++------- .../apix/rest/v1/tests/AllNodeInfoTest.java | 2 +- .../rest/v1/tests/VersionHistoryTest.java | 34 ++++---- .../apix/rest/v2/tests/AllNodeInfoTest.java | 2 +- .../main/java/eu/xenit/apix/data/NodeRef.java | 5 +- .../workflow/model/WorkflowOrTaskChanges.java | 4 + .../staging/workflow/WorkflowClaimsBody.java | 30 +++++++ .../staging/workflow/WorkflowReleaseBody.java | 27 +++++++ .../staging/workflow/WorkflowWebscript.java | 38 ++++----- .../xenit/apix/rest/v1/ApixV1Webscript.java | 25 +++--- .../apix/rest/v1/nodes/ChangeAclsOptions.java | 8 +- .../rest/v1/nodes/ChangeParentOptions.java | 6 +- .../apix/rest/v1/nodes/CreateNodeOptions.java | 17 ++-- .../apix/rest/v1/nodes/InheritFromParent.java | 7 +- .../VersionHistoryWebScript1.java | 1 - .../v1/versionhistory/VersionOptions.java | 9 +++ .../rest/v1/workingcopies/CheckinBody.java | 5 +- .../rest/v1/workingcopies/CheckoutBody.java | 5 +- .../rest/v2/groups/SetSubgroupOptions.java | 4 +- .../v2/groups/SetUsersInGroupOptions.java | 3 + .../webscripts/alfred/api.delete.desc.xml | 2 +- .../webscripts/alfred/api.get.desc.xml | 4 +- .../webscripts/alfred/api.post.desc.xml | 2 +- .../webscripts/alfred/api.put.desc.xml | 2 +- 24 files changed, 218 insertions(+), 103 deletions(-) create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowClaimsBody.java create mode 100644 apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowReleaseBody.java diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4411ffab..ab869958 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,17 +1,42 @@ name: 'Continuous Integration' on: push: - branches: - - 'master*' - - 'release*' - pull_request: workflow_dispatch: +env: + XENIT_ARTIFACTORY_USERNAME: ${{ secrets.XENIT_ARTIFACTORY_USERNAME }} + XENIT_ARTIFACTORY_PASSWORD: ${{ secrets.XENIT_ARTIFACTORY_PASSWORD }} jobs: - BuildAndPublish: + test: + runs-on: ubuntu-latest + steps: + - name: Check out + uses: actions/checkout@v3 + - name: Set up JDK + uses: actions/setup-java@v3 + with: + java-version: 11 + distribution: temurin + - name: Build interface + uses: gradle/gradle-build-action@v2.3.0 + with: + arguments: :apix-interface:build :apix-interface:javadoc + - name: Unit test REST API + uses: gradle/gradle-build-action@v2.3.0 + with: + arguments: --info :apix-rest-v1:test + - name: Upload test reports + if: always() + uses: actions/upload-artifact@v3 + with: + name: test-result + path: /home/runner/work/**/build/reports + retention-days: 2 + integration-test: + runs-on: ubuntu-latest strategy: + fail-fast: false matrix: alfresco_version: [ 62, 70, 71, 72, 73 ] - runs-on: ubuntu-latest steps: - name: Check out uses: actions/checkout@v3 @@ -26,25 +51,8 @@ jobs: registry: private.docker.xenit.eu username: ${{ secrets.CLOUDSMITH_USER }} password: ${{ secrets.CLOUDSMITH_APIKEY }} - - name: Build interface # Execute before integration testing to catch errors early - uses: gradle/gradle-build-action@v2.3.0 - env: - XENIT_ARTIFACTORY_USERNAME: ${{ secrets.XENIT_ARTIFACTORY_USERNAME }} - XENIT_ARTIFACTORY_PASSWORD: ${{ secrets.XENIT_ARTIFACTORY_PASSWORD }} - with: - arguments: :apix-interface:build :apix-interface:javadoc - - name: Unit test REST API + - name: Integration test and apix impl test uses: gradle/gradle-build-action@v2.3.0 - env: - XENIT_ARTIFACTORY_USERNAME: ${{ secrets.XENIT_ARTIFACTORY_USERNAME }} - XENIT_ARTIFACTORY_PASSWORD: ${{ secrets.XENIT_ARTIFACTORY_PASSWORD }} - with: - arguments: --info :apix-rest-v1:test - - name: Build and test - uses: gradle/gradle-build-action@v2.3.0 - env: - XENIT_ARTIFACTORY_USERNAME: ${{ secrets.XENIT_ARTIFACTORY_USERNAME }} - XENIT_ARTIFACTORY_PASSWORD: ${{ secrets.XENIT_ARTIFACTORY_PASSWORD }} with: arguments: >- --info @@ -54,15 +62,28 @@ jobs: if: always() uses: actions/upload-artifact@v3 with: - name: test-result + name: test-result-${{ matrix.alfresco_version }} path: /home/runner/work/**/build/reports retention-days: 2 + publish: + needs: [ test, integration-test ] + runs-on: ubuntu-latest + if: ${{ startsWith(github.ref, 'refs/heads/master') || startsWith(github.ref, 'refs/heads/release') }} + strategy: + fail-fast: false + matrix: + alfresco_version: [ 62, 70, 71, 72, 73 ] + steps: + - name: Check out + uses: actions/checkout@v3 + - name: Set up JDK + uses: actions/setup-java@v3 + with: + java-version: 11 + distribution: temurin - name: Publish - if: ${{ startsWith(github.ref, 'refs/heads/master') || startsWith(github.ref, 'refs/heads/release') }}" uses: gradle/gradle-build-action@v2.3.0 env: - XENIT_ARTIFACTORY_USERNAME: ${{ secrets.XENIT_ARTIFACTORY_USERNAME }} - XENIT_ARTIFACTORY_PASSWORD: ${{ secrets.XENIT_ARTIFACTORY_PASSWORD }} ORG_GRADLE_PROJECT_signingKey: ${{ secrets.MAVEN_CENTRAL_GPG_KEY }} ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.MAVEN_CENTRAL_GPG_PASSWORD }} ORG_GRADLE_PROJECT_sonatype_username: ${{ secrets.SONATYPE_S01_USERNAME }} @@ -71,4 +92,4 @@ jobs: arguments: >- --info -PsigningKeyId=DF8285F0 :apix-interface:publish - :alfresco:${{ matrix.alfresco_version }}:publish + :apix-impl:apix-impl-${{ matrix.alfresco_version }}:publish diff --git a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/AllNodeInfoTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/AllNodeInfoTest.java index 67073409..bee5382e 100644 --- a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/AllNodeInfoTest.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/AllNodeInfoTest.java @@ -81,7 +81,7 @@ public void testGetAllNodeInfoOfMultipleNodes() throws IOException, JSONExceptio @Test public void testGetAllNodeInfoWithNoNodesListed() throws IOException { - String jsonString = json("{}"); + String jsonString = json(""); final CloseableHttpClient httpclient = HttpClients.createDefault(); final String url = makeAlfrescoBaseurl("admin", "admin") + "/apix/v1/nodes/nodeInfo"; diff --git a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java index b149571a..f40b7d0b 100644 --- a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/VersionHistoryTest.java @@ -1,19 +1,12 @@ package eu.xenit.apix.rest.v1.tests; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - import com.fasterxml.jackson.databind.ObjectMapper; import eu.xenit.apix.alfresco.ApixToAlfrescoConversion; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.versionhistory.Version; import eu.xenit.apix.versionhistory.VersionHistory; -import java.io.IOException; -import java.util.HashMap; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.version.VersionBaseModel; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeService; @@ -22,6 +15,7 @@ import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.fluent.Request; +import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; @@ -36,10 +30,17 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import java.io.IOException; +import java.util.HashMap; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + public class VersionHistoryTest extends RestV1BaseTest { - private final static Logger logger = LoggerFactory.getLogger(VersionHistoryTest.class); + private static final Logger logger = LoggerFactory.getLogger(VersionHistoryTest.class); @Autowired @Qualifier("TransactionService") TransactionService transactionService; @@ -119,12 +120,10 @@ public void testSetVersionHistoryWithoutBody() throws IOException { return null; }, true, true); - int statusCode = Request.Put(versionHistoryUrl) + HttpResponse response = Request.Put(versionHistoryUrl) .execute() - .returnResponse() - .getStatusLine() - .getStatusCode(); - assertEquals(200, statusCode); + .returnResponse(); + assertEquals(200, response.getStatusLine().getStatusCode()); transactionService.getRetryingTransactionHelper() .doInTransaction(() -> { @@ -170,12 +169,11 @@ public void testSetVersionHistoryWithoutBody() throws IOException { HttpPut httpPut = new HttpPut(versionHistoryUrl2); httpPut.setEntity(new StringEntity(json(requestBody), ContentType.APPLICATION_JSON)); - int statusCode2 = HttpClients.createDefault() - .execute(httpPut) + CloseableHttpResponse httpResponse = HttpClients.createDefault() + .execute(httpPut); + assertEquals(200, httpResponse .getStatusLine() - .getStatusCode(); - - assertEquals(200, statusCode2); + .getStatusCode()); transactionService.getRetryingTransactionHelper() .doInTransaction(() -> { diff --git a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java index ca8cf569..9a953566 100644 --- a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v2/tests/AllNodeInfoTest.java @@ -80,7 +80,7 @@ public void testGetAllNodeInfoOfMultipleNodes() throws IOException, JSONExceptio @Test public void testGetAllNodeInfoWithNoNodesListed() throws IOException { - String jsonString = json("{}"); + String jsonString = json(""); final CloseableHttpClient httpclient = HttpClients.createDefault(); final String url = makeAlfrescoBaseurl("admin", "admin") + "/apix/v2/nodes/nodeInfo"; diff --git a/apix-interface/src/main/java/eu/xenit/apix/data/NodeRef.java b/apix-interface/src/main/java/eu/xenit/apix/data/NodeRef.java index 0fd74ee3..fc0bc06e 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/data/NodeRef.java +++ b/apix-interface/src/main/java/eu/xenit/apix/data/NodeRef.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; + import java.io.Serializable; /** @@ -14,9 +15,11 @@ public class NodeRef implements Serializable { private static final String FORWARD_SLASH = "/"; private static final String SPACESTORE_DIVIDER = "://"; - private String value; + public NodeRef() { + } + @JsonCreator public NodeRef(String s) { value = s; diff --git a/apix-interface/src/main/java/eu/xenit/apix/workflow/model/WorkflowOrTaskChanges.java b/apix-interface/src/main/java/eu/xenit/apix/workflow/model/WorkflowOrTaskChanges.java index 00ec2423..f90c9f45 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/workflow/model/WorkflowOrTaskChanges.java +++ b/apix-interface/src/main/java/eu/xenit/apix/workflow/model/WorkflowOrTaskChanges.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.Map; public class WorkflowOrTaskChanges { @@ -13,6 +14,9 @@ public WorkflowOrTaskChanges(@JsonProperty("propertiesToSet") Map getPropertiesToSet() { return propertiesToSet; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowClaimsBody.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowClaimsBody.java new file mode 100644 index 00000000..fafc186d --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowClaimsBody.java @@ -0,0 +1,30 @@ +package eu.xenit.apix.rest.staging.workflow; + +public class WorkflowClaimsBody { + private String id; + private String userName; + + public WorkflowClaimsBody(String id, String userName) { + this.id = id; + this.userName = userName; + } + + public WorkflowClaimsBody() { + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } +} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowReleaseBody.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowReleaseBody.java new file mode 100644 index 00000000..93eed4f4 --- /dev/null +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowReleaseBody.java @@ -0,0 +1,27 @@ +package eu.xenit.apix.rest.staging.workflow; + +public class WorkflowReleaseBody { + private String id; + + public WorkflowReleaseBody() { + } + + public WorkflowReleaseBody(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public String toString() { + return "WorkflowReleaseBody{" + + "id='" + id + '\'' + + '}'; + } +} diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java index f4ef63dc..8581fbf0 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java @@ -9,11 +9,6 @@ import eu.xenit.apix.workflow.search.TaskOrWorkflowSearchResult; import eu.xenit.apix.workflow.search.TaskSearchQuery; import eu.xenit.apix.workflow.search.WorkflowSearchQuery; -import java.io.Serializable; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,6 +24,12 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + @RestController public class WorkflowWebscript { private static final Logger logger = LoggerFactory.getLogger(WorkflowWebscript.class); @@ -93,7 +94,7 @@ public ResponseEntity task(@PathVariable final String id) { @PutMapping(value = "/workflows/{id}") public ResponseEntity updateWorkflow(@PathVariable final String id, - @RequestBody final WorkflowOrTaskChanges changes) { + @RequestBody final WorkflowOrTaskChanges changes) { return responseFrom(workflowService.updateWorkflow(id, changes)); } @@ -104,8 +105,8 @@ public ResponseEntity cancelWorkflow(@PathVariable final String id) { } @PutMapping(value = "/tasks/{id}") - public ResponseEntity updateTask(@PathVariable final String id, - @RequestBody final WorkflowOrTaskChanges changes) { + public ResponseEntity updateTask(@PathVariable final String id, + @RequestBody final WorkflowOrTaskChanges changes) { try { return responseFrom(workflowService.updateTask(id, changes)); } catch (Error ex) { @@ -114,27 +115,22 @@ public ResponseEntity updateTask(@PathVariable final String id, } @PostMapping(value = "/staging/tasks/claim") - public ResponseEntity claimTask(@RequestBody final Map body) { - logger.debug("Input: {}", body); - String id = body.get("id"); - String userName = body.get("userName"); - + public ResponseEntity claimTask(@RequestBody final WorkflowClaimsBody workflowClaimsBody) { Task wfTask; - if (userName != null) { - logger.debug("Setting owner of task with id {} to {}", id, userName); - wfTask = workflowService.claimWorkflowTask(id, userName); + if (workflowClaimsBody.getUserName() != null) { + logger.debug("Setting owner of task with id {} to {}", workflowClaimsBody.getId(), workflowClaimsBody.getUserName()); + wfTask = workflowService.claimWorkflowTask(workflowClaimsBody.getId(), workflowClaimsBody.getUserName()); } else { logger.debug("Setting owner of task with id "); - wfTask = workflowService.claimWorkflowTask(id); + wfTask = workflowService.claimWorkflowTask(workflowClaimsBody.getId()); } return responseFrom(wfTask); } @PostMapping(value = "/staging/tasks/release") - public ResponseEntity releaseTask(@RequestBody final Map body) { - logger.debug("Setting owner of task {}", body); - String id = body.get("id"); - Task wfTask = workflowService.releaseWorkflowTask(id); + public ResponseEntity releaseTask(@RequestBody final WorkflowReleaseBody workflowReleaseBody) { + logger.debug("Setting owner of task {}", workflowReleaseBody); + Task wfTask = workflowService.releaseWorkflowTask(workflowReleaseBody.getId()); return responseFrom(wfTask); } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java index e85f2a71..a2086e4e 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java @@ -1,5 +1,6 @@ package eu.xenit.apix.rest.v1; + import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.filefolder.IFileFolderService; import eu.xenit.apix.node.ChildParentAssociation; @@ -63,24 +64,24 @@ protected List nodeRefToNodeInfo(NodeInfoRequest nodeInfoRequest, } protected NodeInfo nodeRefToNodeInfo(NodeRef nodeRef, IFileFolderService fileFolderService, - INodeService nodeService, IPermissionService permissionService) { + INodeService nodeService, IPermissionService permissionService) { return nodeRefToNodeInfo(nodeRef, fileFolderService, nodeService, permissionService, true, true, true, true, true, true, true, true); } protected NodeInfo nodeRefToNodeInfo(NodeRef nodeRef, - IFileFolderService fileFolderService, - INodeService nodeService, - IPermissionService permissionService, - boolean retrievePath, - boolean retrieveMetadata, - boolean retrievePermissions, - boolean retrieveAssocs, - boolean retrieveChildAssocs, - boolean retrieveParentAssocs, - boolean retrieveTargetAssocs, - boolean retrieveSourceAssocs) { + IFileFolderService fileFolderService, + INodeService nodeService, + IPermissionService permissionService, + boolean retrievePath, + boolean retrieveMetadata, + boolean retrievePermissions, + boolean retrieveAssocs, + boolean retrieveChildAssocs, + boolean retrieveParentAssocs, + boolean retrieveTargetAssocs, + boolean retrieveSourceAssocs) { if (!permissionService.hasPermission(nodeRef, IPermissionService.READ)) { logger.warn("Excluding node {} from results due to insufficient permissions", nodeRef); return null; diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeAclsOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeAclsOptions.java index 6dcb374f..c59a1d2e 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeAclsOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeAclsOptions.java @@ -10,8 +10,12 @@ public class ChangeAclsOptions { private boolean inheritFromParent; private Set ownAccessList; - public ChangeAclsOptions( boolean inheritFromParent, - Set ownAccessList) { + public ChangeAclsOptions() { + } + + @JsonCreator + public ChangeAclsOptions(@JsonProperty("inheritFromParent") boolean inheritFromParent, + @JsonProperty("ownAccessList") Set ownAccessList) { this.ownAccessList = ownAccessList; this.inheritFromParent = inheritFromParent; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java index 14d2f3ba..ce2e881a 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java @@ -1,5 +1,8 @@ package eu.xenit.apix.rest.v1.nodes; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + /** * Created by Michiel Huygen on 12/05/2016. */ @@ -8,7 +11,8 @@ class ChangeParentOptions { private String parent; - public ChangeParentOptions(String parent) { + @JsonCreator + public ChangeParentOptions(@JsonProperty("parent") String parent) { this.parent = parent; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java index 0d7bbce3..25f5b9f9 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java @@ -1,5 +1,7 @@ package eu.xenit.apix.rest.v1.nodes; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import eu.xenit.apix.data.QName; import org.alfresco.model.ContentModel; @@ -27,13 +29,14 @@ public CreateNodeOptions() { this.aspectsToAdd = new QName[0]; } - public CreateNodeOptions(String parent, - String name, - String type, - Map properties, - QName[] aspectsToAdd, - QName[] aspectsToRemove, - String copyFrom) { + @JsonCreator + public CreateNodeOptions(@JsonProperty("parent") String parent, + @JsonProperty("name") String name, + @JsonProperty("type") String type, + @JsonProperty("properties") Map properties, + @JsonProperty("aspectsToAdd") QName[] aspectsToAdd, + @JsonProperty("aspectsToRemove") QName[] aspectsToRemove, + @JsonProperty("copyFrom") String copyFrom) { this.parent = parent; this.name = name; this.type = type; diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java index 0b20c763..5ecda553 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/InheritFromParent.java @@ -1,5 +1,8 @@ package eu.xenit.apix.rest.v1.nodes; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + class InheritFromParent { private boolean inheritFromParent; @@ -7,7 +10,9 @@ class InheritFromParent { public InheritFromParent() { } - public InheritFromParent(boolean inheritFromParent) { + + @JsonCreator + public InheritFromParent(@JsonProperty("inheritFromParent") boolean inheritFromParent) { this.inheritFromParent = inheritFromParent; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java index d5fa226b..72733e55 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java @@ -77,7 +77,6 @@ public ResponseEntity deleteVersionHistory(@PathVariable final String space, versionHistoryService.deleteVersionHistory(createNodeRef(space, store, guid)); return ResponseEntity.ok().build(); } - @PutMapping(value = "/v1/versionhistory/{space}/{store}/{guid}") public ResponseEntity setVersionHistory(@PathVariable final String space, @PathVariable final String store, diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionOptions.java index cae4256b..285f1114 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionOptions.java @@ -6,6 +6,15 @@ public class VersionOptions { private Boolean autoVersion; private Boolean autoVersionOnUpdateProps; + public VersionOptions() { + } + + public VersionOptions(Boolean initialVersion, Boolean autoVersion, Boolean autoVersionOnUpdateProps) { + this.initialVersion = initialVersion; + this.autoVersion = autoVersion; + this.autoVersionOnUpdateProps = autoVersionOnUpdateProps; + } + public Boolean getInitialVersion() { return initialVersion; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/CheckinBody.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/CheckinBody.java index 22a493f4..af53d8e9 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/CheckinBody.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/CheckinBody.java @@ -13,11 +13,14 @@ class CheckinBody { @JsonCreator public CheckinBody(@JsonProperty("comment") String comment, - @JsonProperty("majorVersion") boolean majorVersion) { + @JsonProperty("majorVersion") boolean majorVersion) { this.comment = comment; this.majorVersion = majorVersion; } + public CheckinBody() { + } + public String getComment() { return comment; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/CheckoutBody.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/CheckoutBody.java index 2ccb63f9..aaef1c6a 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/CheckoutBody.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/CheckoutBody.java @@ -12,9 +12,12 @@ class CheckoutBody { public NodeRef original; public NodeRef destinationFolder; + public CheckoutBody() { + } + @JsonCreator public CheckoutBody(@JsonProperty("original") NodeRef original, - @JsonProperty("destinationFolder") NodeRef destinationFolder) { + @JsonProperty("destinationFolder") NodeRef destinationFolder) { this.original = original; this.destinationFolder = destinationFolder; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetSubgroupOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetSubgroupOptions.java index d449283e..891ced1f 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetSubgroupOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetSubgroupOptions.java @@ -12,8 +12,10 @@ public SetSubgroupOptions(@JsonProperty("subgroups") String[] subgroups) { this.subgroups = subgroups; } + public SetSubgroupOptions() { + } + public String[] getSubgroups() { return subgroups; } - } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetUsersInGroupOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetUsersInGroupOptions.java index 7aff12a5..25be3c3b 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetUsersInGroupOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/SetUsersInGroupOptions.java @@ -7,6 +7,9 @@ class SetUsersInGroupOptions { private String[] users; + public SetUsersInGroupOptions() { + } + @JsonCreator public SetUsersInGroupOptions(@JsonProperty("users") String[] users) { this.users = users; diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.delete.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.delete.desc.xml index 767beea3..cb177ee8 100644 --- a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.delete.desc.xml +++ b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.delete.desc.xml @@ -4,7 +4,7 @@ user required - + true diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.get.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.get.desc.xml index a927e7d7..b4f8815a 100644 --- a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.get.desc.xml +++ b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.get.desc.xml @@ -2,9 +2,9 @@ Alfred API Get /apix/{path} user - none + required - + true diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.post.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.post.desc.xml index 71b5f35a..d5b0be69 100644 --- a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.post.desc.xml +++ b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.post.desc.xml @@ -4,7 +4,7 @@ user required - + true diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.put.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.put.desc.xml index aa9bd4e8..cc207c3c 100644 --- a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.put.desc.xml +++ b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.put.desc.xml @@ -4,7 +4,7 @@ user required - + true From fb7ac4bdbc9ce1431bcff3bdb620edd56f087785 Mon Sep 17 00:00:00 2001 From: Hechmi Dammak Date: Thu, 27 Apr 2023 13:25:32 +0100 Subject: [PATCH 43/90] ALFREDAPI-518 use AlfrescoTransaction for post delete put and readonly for get mappings --- .github/workflows/ci.yml | 6 +- .../alfresco/comments/CommentService.java | 10 +-- .../ConfigurationServiceImpl.java | 6 +- .../dictionary/DictionaryService.java | 6 +- .../apix/rest/v1/tests/CopyNodeTest.java | 2 +- .../apix/rest/v1/tests/NodesBaseTest.java | 8 +- .../apix/tests/metadata/NodeServiceTest.java | 6 +- .../apix/configuration/ConfigurationFile.java | 11 +++ .../configuration/ConfigurationFileFlags.java | 5 +- .../apix/configuration/Configurations.java | 3 + .../main/java/eu/xenit/apix/data/QName.java | 1 - .../eu/xenit/apix/filefolder/NodePath.java | 8 ++ .../java/eu/xenit/apix/node/NodeMetadata.java | 65 ++++++++++++++-- .../rest/AlfredApiRestServletContext.java | 64 ++++++++++++++-- .../staging/workflow/WorkflowWebscript.java | 21 ++++-- .../ClassificationGetWebscript.java | 6 +- .../DictionaryServiceChecksumWebscript.java | 8 +- .../v0/metadata/MetadataBulkWebscript.java | 2 + .../v0/metadata/MetadataGetWebscript.java | 3 +- .../v0/metadata/MetadataPostWebscript.java | 2 + .../apix/rest/v0/metadata/NodeMetadataV0.java | 74 +++++++++++++++---- .../apix/rest/v0/search/SearchWebScript0.java | 2 + .../xenit/apix/rest/v1/GeneralWebscript.java | 4 +- .../apix/rest/v1/bulk/BulkWebscript1.java | 4 +- .../v1/categories/CategoryWebScript1.java | 4 +- .../ConfigurationWebscript1.java | 7 +- .../v1/dictionary/DictionaryWebScript1.java | 14 +++- .../rest/v1/nodes/ChangeParentOptions.java | 8 +- .../v1/nodes/CreateAssociationOptions.java | 7 +- .../apix/rest/v1/nodes/CreateNodeOptions.java | 57 +++++++------- .../eu/xenit/apix/rest/v1/nodes/NodeInfo.java | 33 +++++---- .../apix/rest/v1/nodes/NodesWebscript1.java | 52 ++++++++----- .../apix/rest/v1/people/PeopleWebscript1.java | 19 +++-- .../v1/properties/PropertiesWebScript1.java | 6 +- .../apix/rest/v1/search/SearchWebScript1.java | 4 +- .../apix/rest/v1/sites/SitesWebscript1.java | 4 +- .../apix/rest/v1/temp/LogsWebscript.java | 5 +- .../xenit/apix/rest/v1/temp/WIPWebscript.java | 6 +- .../translation/TranslationsWebscript1.java | 8 +- .../VersionHistoryWebScript1.java | 14 +++- .../WorkingcopiesWebscript1.java | 8 +- .../apix/rest/v2/groups/GroupsWebscript.java | 22 ++++-- .../apix/rest/v2/nodes/NodesWebscriptV2.java | 9 ++- .../apix/rest/v2/people/PeopleWebscript.java | 25 ++++--- .../webscripts/alfred/api.delete.desc.xml | 2 +- .../webscripts/alfred/api.get.desc.xml | 2 +- .../webscripts/alfred/api.post.desc.xml | 2 +- .../webscripts/alfred/api.put.desc.xml | 2 +- 48 files changed, 454 insertions(+), 193 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ab869958..6d0245c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,10 +69,6 @@ jobs: needs: [ test, integration-test ] runs-on: ubuntu-latest if: ${{ startsWith(github.ref, 'refs/heads/master') || startsWith(github.ref, 'refs/heads/release') }} - strategy: - fail-fast: false - matrix: - alfresco_version: [ 62, 70, 71, 72, 73 ] steps: - name: Check out uses: actions/checkout@v3 @@ -92,4 +88,4 @@ jobs: arguments: >- --info -PsigningKeyId=DF8285F0 :apix-interface:publish - :apix-impl:apix-impl-${{ matrix.alfresco_version }}:publish + :alfresco:publish diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/comments/CommentService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/comments/CommentService.java index 4432ce8c..67fe70b9 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/comments/CommentService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/comments/CommentService.java @@ -112,23 +112,23 @@ protected Comment toComment(org.alfresco.service.cmr.repository.NodeRef document Comment response = new Comment(); response.setId(apixCommentNodeRef); response.setContent(content); - List property = commentMetadata.properties.get(new QName(ContentModel.PROP_TITLE.toString())); + List property = commentMetadata.getProperties().get(new QName(ContentModel.PROP_TITLE.toString())); if (property != null && !property.isEmpty()) { response.setTitle(property.get(0)); } - property = commentMetadata.properties.get(new QName(ContentModel.PROP_CREATED.toString())); + property = commentMetadata.getProperties().get(new QName(ContentModel.PROP_CREATED.toString())); if (property != null && !property.isEmpty()) { response.setCreatedAt(property.get(0)); } - property = commentMetadata.properties.get(new QName(ContentModel.PROP_CREATOR.toString())); + property = commentMetadata.getProperties().get(new QName(ContentModel.PROP_CREATOR.toString())); if (property != null && !property.isEmpty()) { response.setCreatedBy(property.get(0)); } - property = commentMetadata.properties.get(new QName(ContentModel.PROP_MODIFIED.toString())); + property = commentMetadata.getProperties().get(new QName(ContentModel.PROP_MODIFIED.toString())); if (property != null && !property.isEmpty()) { response.setModifiedAt(property.get(0)); } - property = commentMetadata.properties.get(new QName(ContentModel.PROP_MODIFIER.toString())); + property = commentMetadata.getProperties().get(new QName(ContentModel.PROP_MODIFIER.toString())); if (property != null && !property.isEmpty()) { response.setModifiedBy(property.get(0)); } diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java index 051a86b8..8beefa51 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java @@ -111,7 +111,7 @@ public Configurations getConfigurationFiles(String searchDirectory, String nameF ContentInputStream configStream = contentService.getContent(configurationFile.getNodeRef()); if (configStream != null) { String mimetype = configStream.getMimetype(); - String name = configurationFile.getMetadata().properties.get(QNAME_NAME).get(0); + String name = configurationFile.getMetadata().getProperties().get(QNAME_NAME).get(0); logger.debug("Mimetype is {}; filename is {}", mimetype, name); Object parsedContent = null; if (mimetype.equals("text/x-yaml") || name.endsWith(".yaml") || name.endsWith(".yml")) { @@ -144,7 +144,7 @@ private List getChildrenRecursive(NodeRef parent, Configurati for (ChildParentAssociation childParentAssociation : childParentAssociations) { NodeRef child = childParentAssociation.getTarget(); NodeMetadata childMetadata = nodeService.getMetadata(child); - if (childMetadata.type.getValue().equals(QNAME_FOLDER)) { + if (childMetadata.getType().getValue().equals(QNAME_FOLDER)) { files.addAll(getChildrenRecursive(child, filter)); } else if (filter.isAccepted(childMetadata)) { files.add(new ConfigurationFile(child, childMetadata)); @@ -171,7 +171,7 @@ class NameFilter implements ConfigurationServiceImpl.Filter { @Override public boolean isAccepted(NodeMetadata metadata) { - String name = metadata.properties.get(QNAME_NAME).get(0); + String name = metadata.getProperties().get(QNAME_NAME).get(0); logger.debug("Checking if {} matches {}", name, filter); return filter.matcher(name).find(); } diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/DictionaryService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/DictionaryService.java index 18313b7d..9c097de6 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/DictionaryService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/dictionary/DictionaryService.java @@ -37,7 +37,7 @@ @Component("eu.xenit.apix.dictionary.IDictionaryService") public class DictionaryService implements IDictionaryService { - private final static Logger logger = LoggerFactory.getLogger(DictionaryService.class); + private static final Logger logger = LoggerFactory.getLogger(DictionaryService.class); @Autowired private ApixToAlfrescoConversion c; @Autowired @@ -55,8 +55,6 @@ public class DictionaryService implements IDictionaryService { @Autowired private NamespaceService namespaceService; - public DictionaryService() { - } public Namespaces getNamespaces() { Map ret = new HashMap<>(); @@ -65,7 +63,7 @@ public Namespaces getNamespaces() { if (s == null || s.length() == 0) { continue; } - ret.put(s, new Namespace(s, new ArrayList(this.namespaceService.getPrefixes(s)))); + ret.put(s, new Namespace(s, new ArrayList<>(this.namespaceService.getPrefixes(s)))); } return new Namespaces(ret); } diff --git a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java index 868b563b..7e0b8a81 100644 --- a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/CopyNodeTest.java @@ -132,7 +132,7 @@ public void testCopyFileDuplicateName() { @Test public void testCopyFolderDuplicateName() { final NodeRef childRef = nodeService.getChildAssociations(mainTestFolder).get(0).getTarget(); - final String newName = nodeService.getMetadata(childRef).properties.get(c.apix(ContentModel.PROP_NAME)).get(0); + final String newName = nodeService.getMetadata(childRef).getProperties().get(c.apix(ContentModel.PROP_NAME)).get(0); CreateNodeOptions createNodeOptions = getCreateNodeOptions(mainTestFolder, newName, null, null, copyFromFolder); NodeRef newRef = transactionService.getRetryingTransactionHelper() diff --git a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java index 935704ac..89f77609 100644 --- a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/NodesBaseTest.java @@ -107,7 +107,7 @@ public void checkCreatedNode(NodeRef newRef, CreateNodeOptions createNodeOptions assertEquals(createNodeOptions.getParent(), nodeService.getParentAssociations(newRef).get(0).getTarget().toString()); if (createNodeOptions.getType() != null) { - assertEquals(createNodeOptions.getType(), nodeService.getMetadata(newRef).type.toString()); + assertEquals(createNodeOptions.getType(), nodeService.getMetadata(newRef).getType().toString()); } if (createNodeOptions.getCopyFrom() != null) { @@ -116,13 +116,13 @@ public void checkCreatedNode(NodeRef newRef, CreateNodeOptions createNodeOptions if (createNodeOptions.getProperties() != null) { for (Map.Entry property : createNodeOptions.getProperties().entrySet()) { - assertArrayEquals(property.getValue(), nodeService.getMetadata(newRef).properties.get(property.getKey()).toArray()); + assertArrayEquals(property.getValue(), nodeService.getMetadata(newRef).getProperties().get(property.getKey()).toArray()); } } if (createNodeOptions.getAspectsToAdd() != null) { for (QName aspect : createNodeOptions.getAspectsToAdd()) { - assertNotNull(nodeService.getMetadata(newRef).aspects + assertNotNull(nodeService.getMetadata(newRef).getAspects() .stream() .filter(testAspect -> testAspect.equals(aspect)) .findFirst() @@ -132,7 +132,7 @@ public void checkCreatedNode(NodeRef newRef, CreateNodeOptions createNodeOptions if (createNodeOptions.getAspectsToRemove() != null) { for (QName aspect : createNodeOptions.getAspectsToRemove()) { - assertNull(nodeService.getMetadata(newRef).aspects + assertNull(nodeService.getMetadata(newRef).getAspects() .stream() .filter(testAspect -> testAspect.equals(aspect)) .findFirst() diff --git a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/metadata/NodeServiceTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/metadata/NodeServiceTest.java index 76f3f491..add86c16 100644 --- a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/metadata/NodeServiceTest.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/tests/metadata/NodeServiceTest.java @@ -270,14 +270,14 @@ public void TestGetMetadata() { NodeMetadata metadatas = service.getMetadata(c.apix(roots.iterator().next())); logger.debug(metadatas.toString().replaceAll(",", ",\n")); - assertEquals(c.apix(roots.iterator().next()), metadatas.id); + assertEquals(c.apix(roots.iterator().next()), metadatas.getId()); - assertTrue(metadatas.properties.containsKey(c.apix(ContentModel.PROP_NAME))); + assertTrue(metadatas.getProperties().containsKey(c.apix(ContentModel.PROP_NAME))); } private Boolean nodeIsInMetaList(NodeRef node, List metadatas) { for (NodeMetadata metadata : metadatas) { - if (metadata.id.equals(node.toString())) { + if (metadata.getId().equals(node.toString())) { return true; } } diff --git a/apix-interface/src/main/java/eu/xenit/apix/configuration/ConfigurationFile.java b/apix-interface/src/main/java/eu/xenit/apix/configuration/ConfigurationFile.java index c11f0867..2da86883 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/configuration/ConfigurationFile.java +++ b/apix-interface/src/main/java/eu/xenit/apix/configuration/ConfigurationFile.java @@ -17,6 +17,17 @@ public ConfigurationFile(NodeRef nodeRef, NodeMetadata metadata) { this.metadata = metadata; } + public ConfigurationFile() { + } + + public ConfigurationFile(String content, NodeRef nodeRef, NodeMetadata metadata, NodePath path, Object parsedContent) { + this.content = content; + this.nodeRef = nodeRef; + this.metadata = metadata; + this.path = path; + this.parsedContent = parsedContent; + } + public NodeRef getNodeRef() { return nodeRef; } diff --git a/apix-interface/src/main/java/eu/xenit/apix/configuration/ConfigurationFileFlags.java b/apix-interface/src/main/java/eu/xenit/apix/configuration/ConfigurationFileFlags.java index 492c7415..1cb5c49d 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/configuration/ConfigurationFileFlags.java +++ b/apix-interface/src/main/java/eu/xenit/apix/configuration/ConfigurationFileFlags.java @@ -8,8 +8,11 @@ public class ConfigurationFileFlags { public boolean addMetadata; public boolean addNodeRef; + public ConfigurationFileFlags() { + } + public ConfigurationFileFlags(boolean addContent, boolean addPath, boolean addParsedContent, boolean addMetadata, - boolean addNodeRef) { + boolean addNodeRef) { this.addContent = addContent; this.addPath = addPath; this.addParsedContent = addParsedContent; diff --git a/apix-interface/src/main/java/eu/xenit/apix/configuration/Configurations.java b/apix-interface/src/main/java/eu/xenit/apix/configuration/Configurations.java index 795b9021..799219de 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/configuration/Configurations.java +++ b/apix-interface/src/main/java/eu/xenit/apix/configuration/Configurations.java @@ -7,6 +7,9 @@ public class Configurations { private List files; + public Configurations() { + } + public Configurations(List files) { this.files = new ArrayList<>(files); this.files.sort(new ConfigurationFileComparator()); diff --git a/apix-interface/src/main/java/eu/xenit/apix/data/QName.java b/apix-interface/src/main/java/eu/xenit/apix/data/QName.java index cf8c5c69..84d9ec96 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/data/QName.java +++ b/apix-interface/src/main/java/eu/xenit/apix/data/QName.java @@ -1,7 +1,6 @@ package eu.xenit.apix.data; import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.JsonValue; import java.io.Serializable; diff --git a/apix-interface/src/main/java/eu/xenit/apix/filefolder/NodePath.java b/apix-interface/src/main/java/eu/xenit/apix/filefolder/NodePath.java index 576f17da..9ce72315 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/filefolder/NodePath.java +++ b/apix-interface/src/main/java/eu/xenit/apix/filefolder/NodePath.java @@ -9,6 +9,14 @@ public class NodePath { private String displayPath; private String qnamePath; + public NodePath() { + } + + public NodePath(String displayPath, String qnamePath) { + this.displayPath = displayPath; + this.qnamePath = qnamePath; + } + public String getDisplayPath() { return displayPath; } diff --git a/apix-interface/src/main/java/eu/xenit/apix/node/NodeMetadata.java b/apix-interface/src/main/java/eu/xenit/apix/node/NodeMetadata.java index e11897da..af541cd6 100644 --- a/apix-interface/src/main/java/eu/xenit/apix/node/NodeMetadata.java +++ b/apix-interface/src/main/java/eu/xenit/apix/node/NodeMetadata.java @@ -14,13 +14,15 @@ */ public class NodeMetadata { - public NodeRef id; - public QName type; // qname - public QName baseType; //qname - public long transactionId; - public Map> properties;//: { [k: string]: Translation[]; } - public List aspects; - //TODO: parent + private NodeRef id; + private QName type; // qname + private QName baseType; //qname + private long transactionId; + private Map> properties;//: { [k: string]: Translation[]; } + private List aspects; + + public NodeMetadata() { + } public NodeMetadata(NodeRef id, QName type, QName baseType, long transactionId, Map> properties, List aspects) { @@ -32,6 +34,55 @@ public NodeMetadata(NodeRef id, QName type, QName baseType, long transactionId, this.aspects = aspects; } + public NodeRef getId() { + return id; + } + + public void setId(NodeRef id) { + this.id = id; + } + + public QName getType() { + return type; + } + + public void setType(QName type) { + this.type = type; + } + + public QName getBaseType() { + return baseType; + } + + public void setBaseType(QName baseType) { + this.baseType = baseType; + } + + public long getTransactionId() { + return transactionId; + } + + public void setTransactionId(long transactionId) { + this.transactionId = transactionId; + } + + public Map> getProperties() { + return properties; + } + + public void setProperties(Map> properties) { + this.properties = properties; + } + //TODO: parent + + public List getAspects() { + return aspects; + } + + public void setAspects(List aspects) { + this.aspects = aspects; + } + @Override public String toString() { return "NodeMetadata{" + diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java index 37d9d2e7..27308d08 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/AlfredApiRestServletContext.java @@ -4,11 +4,37 @@ import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; +import com.gradecak.alfresco.mvc.annotation.EnableAlfrescoMvcAop; import com.gradecak.alfresco.mvc.rest.config.DefaultAlfrescoMvcServletContextConfiguration; import eu.xenit.apix.rest.jackson.Jackson2ApixNodeRefDeserializer; import eu.xenit.apix.rest.jackson.Jackson2ApixNodeRefSerializer; import eu.xenit.apix.rest.jackson.Jackson2ApixQnameDeserializer; import eu.xenit.apix.rest.jackson.Jackson2ApixQnameSerializer; +import eu.xenit.apix.rest.staging.workflow.WorkflowWebscript; +import eu.xenit.apix.rest.v0.categories.ClassificationGetWebscript; +import eu.xenit.apix.rest.v0.dictionary.DictionaryServiceChecksumWebscript; +import eu.xenit.apix.rest.v0.metadata.MetadataBulkWebscript; +import eu.xenit.apix.rest.v0.metadata.MetadataGetWebscript; +import eu.xenit.apix.rest.v0.metadata.MetadataPostWebscript; +import eu.xenit.apix.rest.v0.search.SearchWebScript0; +import eu.xenit.apix.rest.v1.GeneralWebscript; +import eu.xenit.apix.rest.v1.bulk.BulkWebscript1; +import eu.xenit.apix.rest.v1.categories.CategoryWebScript1; +import eu.xenit.apix.rest.v1.configuration.ConfigurationWebscript1; +import eu.xenit.apix.rest.v1.dictionary.DictionaryWebScript1; +import eu.xenit.apix.rest.v1.nodes.NodesWebscript1; +import eu.xenit.apix.rest.v1.people.PeopleWebscript1; +import eu.xenit.apix.rest.v1.properties.PropertiesWebScript1; +import eu.xenit.apix.rest.v1.search.SearchWebScript1; +import eu.xenit.apix.rest.v1.sites.SitesWebscript1; +import eu.xenit.apix.rest.v1.temp.LogsWebscript; +import eu.xenit.apix.rest.v1.temp.WIPWebscript; +import eu.xenit.apix.rest.v1.translation.TranslationsWebscript1; +import eu.xenit.apix.rest.v1.versionhistory.VersionHistoryWebScript1; +import eu.xenit.apix.rest.v1.workingcopies.WorkingcopiesWebscript1; +import eu.xenit.apix.rest.v2.groups.GroupsWebscript; +import eu.xenit.apix.rest.v2.nodes.NodesWebscriptV2; +import eu.xenit.apix.rest.v2.people.PeopleWebscript; import eu.xenit.apix.search.json.SearchNodeJsonParser; import org.alfresco.rest.framework.jacksonextensions.RestJsonModule; import org.alfresco.service.namespace.NamespaceService; @@ -27,9 +53,37 @@ @Configuration @EnableWebMvc -@PropertySource(value = { "classpath:application.properties" }) +@PropertySource(value = {"classpath:application.properties"}) // should pick up other controllers from the same package by default -@ComponentScan(basePackages = { "eu.xenit.apix" }) +@ComponentScan(basePackages = {"eu.xenit.apix"}) +@EnableAlfrescoMvcAop(basePackageClasses = { + BulkWebscript1.class, + CategoryWebScript1.class, + ConfigurationWebscript1.class, + ClassificationGetWebscript.class, + DictionaryWebScript1.class, + DictionaryServiceChecksumWebscript.class, + GeneralWebscript.class, + GroupsWebscript.class, + LogsWebscript.class, + MetadataPostWebscript.class, + MetadataBulkWebscript.class, + MetadataGetWebscript.class, + NodesWebscriptV2.class, + NodesWebscript1.class, + PropertiesWebScript1.class, + PeopleWebscript1.class, + PeopleWebscript1.class, + PeopleWebscript.class, + SearchWebScript1.class, + SearchWebScript0.class, + SitesWebscript1.class, + TranslationsWebscript1.class, + VersionHistoryWebScript1.class, + WorkingcopiesWebscript1.class, + WorkflowWebscript.class, + WIPWebscript.class +}) public class AlfredApiRestServletContext extends DefaultAlfrescoMvcServletContextConfiguration { @@ -40,8 +94,8 @@ public AlfredApiRestServletContext(RestJsonModule alfrescoRestJsonModule, Namesp @Override protected List> customJsonDeserializers() { return Arrays.asList( - new Jackson2ApixNodeRefDeserializer(), - new Jackson2ApixQnameDeserializer() + new Jackson2ApixNodeRefDeserializer(), + new Jackson2ApixQnameDeserializer() ); } @@ -74,7 +128,7 @@ public boolean isMultipart(HttpServletRequest request) { return false; } String contentType = request.getContentType(); - return (contentType != null &&contentType.toLowerCase().startsWith("multipart/")); + return (contentType != null && contentType.toLowerCase().startsWith("multipart/")); } }; resolver.setMaxUploadSize(-1); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java index 8581fbf0..6a70a467 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/staging/workflow/WorkflowWebscript.java @@ -1,5 +1,6 @@ package eu.xenit.apix.rest.staging.workflow; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.workflow.IWorkflowService; import eu.xenit.apix.workflow.model.Task; import eu.xenit.apix.workflow.model.Workflow; @@ -39,7 +40,7 @@ public class WorkflowWebscript { public WorkflowWebscript(@Qualifier("eu.xenit.apix.workflow.IWorkflowService") IWorkflowService workflowService) { this.workflowService = workflowService; } - + @AlfrescoTransaction(readOnly = true) @GetMapping( value = "/staging/workflows/definitions", produces = MediaType.APPLICATION_JSON_VALUE @@ -56,11 +57,13 @@ public ResponseEntity getWorkflowDefinitions( return responseFrom(new WorkflowDefinitionList(definitions)); } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/workflows/definition/{name}") public ResponseEntity getWorkflowDefinition(@PathVariable final String name) { return responseFrom(workflowService.getWorkflowDefinition(name)); } + @AlfrescoTransaction @PostMapping(value = "/workflows/search") public ResponseEntity workflowsActiviti(@RequestBody final WorkflowSearchQuery query) { TaskOrWorkflowSearchResult result = workflowService.searchWorkflows(query); @@ -69,51 +72,57 @@ public ResponseEntity workflowsActiviti(@RequestBody return responseFrom(result); } + @AlfrescoTransaction @PostMapping(value = "/tasks/search") public ResponseEntity tasksActiviti(@RequestBody final TaskSearchQuery query) { return responseFrom(workflowService.searchTasks(query)); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/workflows/{id}") public ResponseEntity workflow(@PathVariable final String id) { return responseFrom(workflowService.getWorkflowInfo(id)); } + @AlfrescoTransaction @PostMapping(value = "/workflows/{id}/start") public ResponseEntity startWorkflow(@PathVariable final String id, @RequestBody final Map variables) { logger.debug("variables: {}", variables); return responseFrom(workflowService.startWorkflow(id, variables)); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/tasks/{id}") public ResponseEntity task(@PathVariable final String id) { responseFrom(workflowService.getTaskInfo(id)); return ResponseEntity.ok().build(); } + @AlfrescoTransaction @PutMapping(value = "/workflows/{id}") public ResponseEntity updateWorkflow(@PathVariable final String id, @RequestBody final WorkflowOrTaskChanges changes) { return responseFrom(workflowService.updateWorkflow(id, changes)); } + @AlfrescoTransaction @DeleteMapping(value = "/workflows/{id}") public ResponseEntity cancelWorkflow(@PathVariable final String id) { workflowService.cancelWorkflow(id); return ResponseEntity.ok().build(); } + @AlfrescoTransaction @PutMapping(value = "/tasks/{id}") public ResponseEntity updateTask(@PathVariable final String id, @RequestBody final WorkflowOrTaskChanges changes) { try { return responseFrom(workflowService.updateTask(id, changes)); - } catch (Error ex) { + } catch (Exception ex) { return ResponseEntity.status(HttpStatus.SC_CONFLICT).build(); } } + @AlfrescoTransaction @PostMapping(value = "/staging/tasks/claim") public ResponseEntity claimTask(@RequestBody final WorkflowClaimsBody workflowClaimsBody) { Task wfTask; @@ -127,6 +136,7 @@ public ResponseEntity claimTask(@RequestBody final WorkflowClaimsBody work return responseFrom(wfTask); } + @AlfrescoTransaction @PostMapping(value = "/staging/tasks/release") public ResponseEntity releaseTask(@RequestBody final WorkflowReleaseBody workflowReleaseBody) { logger.debug("Setting owner of task {}", workflowReleaseBody); @@ -134,11 +144,12 @@ public ResponseEntity releaseTask(@RequestBody final WorkflowReleaseBody w return responseFrom(wfTask); } + @AlfrescoTransaction @PostMapping(value = "/staging/tasks/{id}/end/{transition}") public void transitionTask(@PathVariable String id, @PathVariable String transition) { workflowService.endTask(id, transition); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/staging/workflows/generate/{amount}/{username}") public void generateWorkflow(@PathVariable final int amount, @PathVariable final String username) { workflowService.GenerateWorkflows(amount, username); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/categories/ClassificationGetWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/categories/ClassificationGetWebscript.java index 67b42397..0bc99c70 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/categories/ClassificationGetWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/categories/ClassificationGetWebscript.java @@ -1,16 +1,17 @@ package eu.xenit.apix.rest.v0.categories; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.categories.Category; import eu.xenit.apix.categories.ICategoryService; import eu.xenit.apix.data.QName; -import java.util.List; - import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + @RestController public class ClassificationGetWebscript { @@ -20,6 +21,7 @@ public ClassificationGetWebscript(ICategoryService catService) { this.catService = catService; } + @AlfrescoTransaction(readOnly = true) @GetMapping( value = "/classification/{aspectQName}", produces = MediaType.APPLICATION_JSON_VALUE diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/dictionary/DictionaryServiceChecksumWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/dictionary/DictionaryServiceChecksumWebscript.java index e30cbae0..1dc5c1b8 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/dictionary/DictionaryServiceChecksumWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/dictionary/DictionaryServiceChecksumWebscript.java @@ -1,14 +1,15 @@ package eu.xenit.apix.rest.v0.dictionary; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.dictionary.IDictionaryService; -import java.util.Collections; -import java.util.Map; - import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.Collections; +import java.util.Map; + @RestController public class DictionaryServiceChecksumWebscript { @@ -18,6 +19,7 @@ public DictionaryServiceChecksumWebscript(IDictionaryService service) { this.service = service; } + @AlfrescoTransaction(readOnly = true) @GetMapping( value = "/dictionary/checksum", produces = MediaType.APPLICATION_JSON_VALUE diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataBulkWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataBulkWebscript.java index 48b0e762..ab10a20c 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataBulkWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataBulkWebscript.java @@ -1,5 +1,6 @@ package eu.xenit.apix.rest.v0.metadata; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.node.INodeService; import eu.xenit.apix.permissions.IPermissionService; @@ -23,6 +24,7 @@ public MetadataBulkWebscript(INodeService service, IPermissionService permission this.permissionService = permissionService; } + @AlfrescoTransaction @PostMapping( value = "/eu/xenit/metadata/bulk", produces = MediaType.APPLICATION_JSON_VALUE diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataGetWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataGetWebscript.java index f7493635..99bd8357 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataGetWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataGetWebscript.java @@ -1,5 +1,6 @@ package eu.xenit.apix.rest.v0.metadata; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.node.INodeService; import eu.xenit.apix.permissions.IPermissionService; @@ -18,7 +19,7 @@ public MetadataGetWebscript(INodeService service, IPermissionService permissionS this.service = service; this.permissionService = permissionService; } - + @AlfrescoTransaction(readOnly = true) @GetMapping( value = "/eu/xenit/metadata", produces = MediaType.APPLICATION_JSON_VALUE diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataPostWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataPostWebscript.java index 7ac68299..c0edf019 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataPostWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/MetadataPostWebscript.java @@ -1,5 +1,6 @@ package eu.xenit.apix.rest.v0.metadata; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.node.INodeService; import eu.xenit.apix.permissions.IPermissionService; @@ -21,6 +22,7 @@ public MetadataPostWebscript(INodeService service, IPermissionService permission this.permissionService = permissionService; } + @AlfrescoTransaction @PostMapping( value = "/eu/xenit/metadata", produces = MediaType.APPLICATION_JSON_VALUE diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/NodeMetadataV0.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/NodeMetadataV0.java index 1d0b770d..7504185c 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/NodeMetadataV0.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/metadata/NodeMetadataV0.java @@ -5,6 +5,7 @@ import eu.xenit.apix.node.NodeMetadata; import eu.xenit.apix.permissions.IPermissionService; import eu.xenit.apix.permissions.PermissionValue; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -16,21 +17,20 @@ */ public class NodeMetadataV0 { - public String id; - public String type; // qname + public boolean canEditMetadata; // TODO: remove + private String id; + private String type; // qname //public String qnamePath;// Whats difference between qname and qnamepath //public String icon16; // REMOVE //public String icon32; // REMOVE //public String mimetype; // REMOVE //public boolean isVersioned; // REMOVE - public long transactionId; + private long transactionId; //TODO: cleanup - public Map> properties;//: { [k: string]: Translation[]; } - public List aspects; + private Map> properties;//: { [k: string]: Translation[]; } //TODO: associations //TODO: parent - - public boolean canEditMetadata; // TODO: remove + private List aspects; //public NodeAssociation[] associations; @@ -39,13 +39,13 @@ public class NodeMetadataV0 { public static NodeMetadataV0 FromV1(NodeMetadata m, IPermissionService permissionService) { NodeMetadataV0 ret = new NodeMetadataV0(); - ret.id = m.id.getValue(); - ret.type = m.type.getValue(); - ret.transactionId = m.transactionId; + ret.id = m.getId().getValue(); + ret.type = m.getType().getValue(); + ret.transactionId = m.getTransactionId(); ret.properties = new HashMap<>(); ret.aspects = new ArrayList<>(); - for (Map.Entry> e : m.properties.entrySet()) { + for (Map.Entry> e : m.getProperties().entrySet()) { List ts = null; if (e != null) { ts = new ArrayList<>(); @@ -56,17 +56,65 @@ public static NodeMetadataV0 FromV1(NodeMetadata m, IPermissionService permissio ret.properties.put(e.getKey().getValue(), ts); } - for (QName a : m.aspects) { + for (QName a : m.getAspects()) { ret.aspects.add(a.getValue()); } - Map perms = permissionService.getPermissions(m.id); + Map perms = permissionService.getPermissions(m.getId()); ret.canEditMetadata = perms.containsKey(IPermissionService.WRITE) && perms.get(IPermissionService.WRITE) == PermissionValue.ALLOW; return ret; } + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public long getTransactionId() { + return transactionId; + } + + public void setTransactionId(long transactionId) { + this.transactionId = transactionId; + } + + public Map> getProperties() { + return properties; + } + + public void setProperties(Map> properties) { + this.properties = properties; + } + + public List getAspects() { + return aspects; + } + + public void setAspects(List aspects) { + this.aspects = aspects; + } + + public boolean isCanEditMetadata() { + return canEditMetadata; + } + + public void setCanEditMetadata(boolean canEditMetadata) { + this.canEditMetadata = canEditMetadata; + } + @Override public String toString() { return "NodeMetadata{" + diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchWebScript0.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchWebScript0.java index 7bb1ab91..ec03d3fb 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchWebScript0.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v0/search/SearchWebScript0.java @@ -1,5 +1,6 @@ package eu.xenit.apix.rest.v0.search; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.search.ISearchService; import eu.xenit.apix.search.SearchQueryResult; import org.slf4j.Logger; @@ -19,6 +20,7 @@ public SearchWebScript0(ISearchService service) { this.service = service; } + @AlfrescoTransaction @PostMapping( value = "/eu/xenit/search", produces = MediaType.APPLICATION_JSON_VALUE diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java index d06d20a6..f70edcf8 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/GeneralWebscript.java @@ -1,6 +1,7 @@ package eu.xenit.apix.rest.v1; import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.version.IVersionService; import eu.xenit.apix.version.VersionDescription; @@ -9,7 +10,7 @@ import org.springframework.web.bind.annotation.RestController; @AlfrescoAuthentication(AuthenticationType.USER) -@RestController("eu.xenit.apix.rest.v1.GeneralWebscript") +@RestController public class GeneralWebscript extends ApixV1Webscript { private final IVersionService versionService; @@ -18,6 +19,7 @@ public GeneralWebscript(IVersionService versionService) { this.versionService = versionService; } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/version") public ResponseEntity getApixVersion() { return writeJsonResponse(versionService.getVersionDescription()); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java index fe93596c..0a8569f7 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.webscript.DispatcherWebscript; import eu.xenit.apix.rest.v1.ApixV1Webscript; import eu.xenit.apix.rest.v1.bulk.request.BulkHttpServletRequest; @@ -30,7 +31,7 @@ import java.util.stream.Collectors; -@RestController("eu.xenit.apix.rest.v1.BulkWebscript") +@RestController public class BulkWebscript1 extends ApixV1Webscript { private static final Logger logger = LoggerFactory.getLogger(BulkWebscript1.class); @@ -45,6 +46,7 @@ public BulkWebscript1(ServiceRegistry serviceRegistry, this.dispatcherWebscript = dispatcherWebscript; } + @AlfrescoTransaction @PostMapping(value = "/v1/bulk") public ResponseEntity> bulk(@RequestBody final BulkRequest[] bulkRequests, final HttpServletRequest req) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java index 71bd235a..1cfd9bad 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java @@ -1,6 +1,7 @@ package eu.xenit.apix.rest.v1.categories; import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.categories.Category; import eu.xenit.apix.categories.ICategoryService; @@ -13,7 +14,7 @@ import org.springframework.web.bind.annotation.RestController; @AlfrescoAuthentication(AuthenticationType.USER) -@RestController("eu.xenit.apix.rest.v1.categories.CategoryWebScript1") +@RestController public class CategoryWebScript1 extends ApixV1Webscript { private final ICategoryService categoryService; @@ -22,6 +23,7 @@ public CategoryWebScript1(ICategoryService categoryService) { this.categoryService = categoryService; } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/category/aspect/{qname}") public ResponseEntity getCategoriesForAspect(@PathVariable final String qname) { QName apixQName = new QName(qname); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java index 6e4dbef2..75f361ff 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.ObjectMapper; import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.configuration.ConfigurationFileFlags; import eu.xenit.apix.configuration.ConfigurationService; @@ -25,7 +26,7 @@ import org.springframework.web.bind.annotation.RestController; @AlfrescoAuthentication(AuthenticationType.USER) -@RestController("eu.xenit.apix.rest.v1.configuration.ConfigurationWebscript1") +@RestController public class ConfigurationWebscript1 extends ApixV1Webscript { private static final Logger log = LoggerFactory.getLogger(ConfigurationWebscript1.class); @@ -43,7 +44,7 @@ public ConfigurationWebscript1( mapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/configuration", consumes = {"application/js"}, produces = {"application/js"}) public ResponseEntity getJsConfigurationFiles( @RequestParam(defaultValue = "content,nodeRef", required = false) String[] fields, @@ -66,7 +67,7 @@ public ResponseEntity getJsConfigurationFiles( mapper.writeValueAsString(configurations))); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/configuration" , consumes = {MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_JSON_VALUE}) diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java index 021c431e..7f1551c7 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java @@ -1,6 +1,7 @@ package eu.xenit.apix.rest.v1.dictionary; import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.data.QName; import eu.xenit.apix.dictionary.IDictionaryService; @@ -23,7 +24,7 @@ import javax.servlet.http.HttpServletRequest; @AlfrescoAuthentication(AuthenticationType.USER) -@RestController("eu.xenit.apix.rest.v1.property.DictionaryWebScript1") +@RestController public class DictionaryWebScript1 extends ApixV1Webscript { private static final Logger logger = LoggerFactory.getLogger(DictionaryWebScript1.class); @@ -34,6 +35,7 @@ public DictionaryWebScript1( this.dictionaryService = dictionaryService; } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/dictionary/properties/**") public ResponseEntity getPropertyDefinition(HttpServletRequest request) { QName qname = extractQNameFromUrlPath(request, "/v1/dictionary/properties/"); @@ -44,15 +46,15 @@ public ResponseEntity getPropertyDefinition(HttpServletRequest request) { return writeJsonResponse(propDef); } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/dictionary/properties") public ResponseEntity getProperties() { return writeJsonResponse(dictionaryService.getProperties()); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/dictionary/types") - public ResponseEntity getSubTypeDefinitions(@RequestParam(defaultValue = "sys:base", required = false) - final String parent) { + public ResponseEntity getSubTypeDefinitions(@RequestParam(defaultValue = "sys:base", required = false) final String parent) { return writeJsonResponse( dictionaryService.GetSubTypeDefinitions( new QName(parent), true @@ -60,6 +62,7 @@ public ResponseEntity getSubTypeDefinitions(@RequestParam(defaultValue = ); } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/dictionary/types/**") public ResponseEntity getTypeDefinition(HttpServletRequest request) { QName qname = extractQNameFromUrlPath(request, "/v1/dictionary/types/"); @@ -71,6 +74,7 @@ public ResponseEntity getTypeDefinition(HttpServletRequest request) { return writeJsonResponse(classDef); } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/dictionary/aspects/**") public ResponseEntity getAspectDefinition(HttpServletRequest request) { QName qname = extractQNameFromUrlPath(request, "/v1/dictionary/aspects/"); @@ -82,11 +86,13 @@ public ResponseEntity getAspectDefinition(HttpServletRequest request) { return writeJsonResponse(classDef); } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/dictionary/aspects") public ResponseEntity getAspects() { return writeJsonResponse(dictionaryService.getAspects()); } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/dictionary/namespaces") public ResponseEntity getNamespaces() { return writeJsonResponse(dictionaryService.getNamespaces()); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java index ce2e881a..38b31df2 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/ChangeParentOptions.java @@ -19,11 +19,11 @@ public ChangeParentOptions(@JsonProperty("parent") String parent) { public ChangeParentOptions() { } - public void setParent(String parent) { - this.parent = parent; - } - public String getParent() { return parent; } + + public void setParent(String parent) { + this.parent = parent; + } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateAssociationOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateAssociationOptions.java index e96951d5..37a70cdf 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateAssociationOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateAssociationOptions.java @@ -7,17 +7,16 @@ * Created by Michiel Huygen on 23/05/2016. */ public class CreateAssociationOptions { + private NodeRef target; + private QName type = new QName("{http://www.alfresco.org/model/content/1.0}content"); + public CreateAssociationOptions(NodeRef target, QName type) { this.target = target; this.type = type; } - public CreateAssociationOptions() { } - private NodeRef target; - private QName type = new QName("{http://www.alfresco.org/model/content/1.0}content"); - public NodeRef getTarget() { return target; } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java index 25f5b9f9..bc941cc5 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/CreateNodeOptions.java @@ -55,60 +55,59 @@ public CreateNodeOptions(@JsonProperty("parent") String parent, this.copyFrom = copyFrom; } - public void setParent(String parent) { - this.parent = parent; - } - - public void setName(String name) { - this.name = name; - } - - public void setType(String type) { - this.type = type; - } - - public void setProperties(Map properties) { - this.properties = properties; - } - - public void setAspectsToAdd(QName[] aspectsToAdd) { - this.aspectsToAdd = aspectsToAdd; - } - - public void setAspectsToRemove(QName[] aspectsToRemove) { - this.aspectsToRemove = aspectsToRemove; - } - - public void setCopyFrom(String copyFrom) { - this.copyFrom = copyFrom; - } - - public String getParent() { return parent; } + public void setParent(String parent) { + this.parent = parent; + } + public String getName() { return name; } + public void setName(String name) { + this.name = name; + } + public String getType() { return type; } + public void setType(String type) { + this.type = type; + } + public Map getProperties() { return properties; } + public void setProperties(Map properties) { + this.properties = properties; + } + public QName[] getAspectsToAdd() { return aspectsToAdd; } + public void setAspectsToAdd(QName[] aspectsToAdd) { + this.aspectsToAdd = aspectsToAdd; + } + public QName[] getAspectsToRemove() { return aspectsToRemove; } + public void setAspectsToRemove(QName[] aspectsToRemove) { + this.aspectsToRemove = aspectsToRemove; + } + public String getCopyFrom() { return copyFrom; } + + public void setCopyFrom(String copyFrom) { + this.copyFrom = copyFrom; + } } diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodeInfo.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodeInfo.java index 38d3b366..8f0aff3c 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodeInfo.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodeInfo.java @@ -5,6 +5,7 @@ import eu.xenit.apix.node.NodeAssociations; import eu.xenit.apix.node.NodeMetadata; import eu.xenit.apix.permissions.PermissionValue; + import java.util.Map; /** @@ -18,6 +19,22 @@ public class NodeInfo { private NodeAssociations associations; private NodePath path; + public NodeInfo() { + + } + + public NodeInfo(NodeRef nodeRef, + NodeMetadata metadata, + Map permissions, + NodeAssociations associations, + NodePath path) { + this.noderef = nodeRef; + this.metadata = metadata; + this.permissions = permissions; + this.associations = associations; + this.path = path; + } + public NodeRef getNoderef() { return noderef; } @@ -57,20 +74,4 @@ public NodePath getPath() { public void setPath(NodePath path) { this.path = path; } - - public NodeInfo() { - - } - - public NodeInfo(NodeRef nodeRef, - NodeMetadata metadata, - Map permissions, - NodeAssociations associations, - NodePath path) { - this.noderef = nodeRef; - this.metadata = metadata; - this.permissions = permissions; - this.associations = associations; - this.path = path; - } } \ No newline at end of file diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java index 166a1c26..e18e4385 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/nodes/NodesWebscript1.java @@ -52,7 +52,7 @@ @AlfrescoTransaction -@RestController("eu.xenit.apix.rest.v1.NodesWebscript") +@RestController public class NodesWebscript1 extends ApixV1Webscript { private static final Logger logger = LoggerFactory.getLogger(NodesWebscript1.class); @@ -77,6 +77,7 @@ public NodesWebscript1(INodeService nodeService, IPermissionService permissionSe this.serviceRegistry = serviceRegistry; } + @AlfrescoTransaction @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/metadata") public ResponseEntity setMetadata(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid, @RequestBody final MetadataChanges changes) { @@ -87,7 +88,7 @@ public ResponseEntity setMetadata(@PathVariable final String space } return writeJsonResponse(nodeMetadata); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/metadata") public ResponseEntity getMetadata(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -101,7 +102,7 @@ public ResponseEntity getMetadata(@PathVariable String space, @Pat } } - + @AlfrescoTransaction @DeleteMapping(value = "/v1/nodes/{space}/{store}/{guid}") public ResponseEntity deleteNode(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid, @@ -119,7 +120,7 @@ public ResponseEntity deleteNode(@PathVariable final String space, @Path .status(HttpStatus.SC_NOT_FOUND) .body(String.format("Failed to delete node, node does not exist: %s", nodeRef.toString())); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations") public ResponseEntity getAssociations(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -130,6 +131,7 @@ public ResponseEntity getAssociations(@PathVariable String spa ); } + @AlfrescoTransaction @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations") public ResponseEntity createAssociation(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @@ -142,6 +144,7 @@ public ResponseEntity createAssociation(@PathVariable String space, @PathV return ResponseEntity.ok().build(); } + @AlfrescoTransaction @DeleteMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations") public ResponseEntity deleteAssociation(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestParam NodeRef target, @@ -154,7 +157,7 @@ public ResponseEntity deleteAssociation(@PathVariable String space, @PathV return ResponseEntity.ok().build(); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations/parents") public ResponseEntity> getParentAssociations(@PathVariable String space, @PathVariable String store, @@ -165,7 +168,7 @@ public ResponseEntity> getParentAssociations(@PathV ) ); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations/children") public ResponseEntity> getChildAssociations(@PathVariable String space, @PathVariable String store, @@ -176,7 +179,7 @@ public ResponseEntity> getChildAssociations(@PathVa ) ); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/associations/targets") public ResponseEntity> getSourcePeerAssociations(@PathVariable String space, @PathVariable String store, @@ -187,7 +190,7 @@ public ResponseEntity> getSourcePeerAssociations(@PathVari ) ); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/permissions") // It would seem permissions can always be retrieved? public ResponseEntity> getPermissions(@PathVariable String space, @@ -200,6 +203,7 @@ public ResponseEntity> getPermissions(@PathVariable ); } + @AlfrescoTransaction @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/permissions/authority/{authority}/permission/{permission}") public ResponseEntity setPermission(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @PathVariable String authority, @@ -210,6 +214,7 @@ public ResponseEntity setPermission(@PathVariable String space, @PathVaria return ResponseEntity.ok().build(); } + @AlfrescoTransaction @DeleteMapping(value = "/v1/nodes/{space}/{store}/{guid}/permissions/authority/{authority}/permission/{permission}") public ResponseEntity deletePermission(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @PathVariable String authority, @@ -217,7 +222,7 @@ public ResponseEntity deletePermission(@PathVariable String space, @PathVa this.permissionService.deletePermission(this.createNodeRef(space, store, guid), authority, permission); return ResponseEntity.ok().build(); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/acl") public ResponseEntity getAcls(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -228,6 +233,7 @@ public ResponseEntity getAcls(@PathVariable String space, @PathV ); } + @AlfrescoTransaction @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/acl/inheritFromParent") public void setInheritParentPermissions(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestBody final InheritFromParent inherit) { @@ -236,6 +242,7 @@ public void setInheritParentPermissions(@PathVariable String space, @PathVariabl ); } + @AlfrescoTransaction @PutMapping(value = "/v1/nodes/{space}/{store}/{guid}/acl") public ResponseEntity setAcls(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @@ -260,7 +267,7 @@ public ResponseEntity setAcls(@PathVariable String space, @PathVariable St ); return ResponseEntity.ok().build(); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/path") public ResponseEntity getPath(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -270,7 +277,7 @@ public ResponseEntity getPath(@PathVariable String space, @PathVariabl ) ); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}") public ResponseEntity getAllInfoOfNode(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -295,6 +302,7 @@ public ResponseEntity getAllInfoOfNode(@PathVariable String space, @Path } } + @AlfrescoTransaction @PostMapping(value = "/v1/nodes/nodeInfo") public ResponseEntity getAllInfoOfNodes(@RequestBody final NodeInfoRequest nodeInfoRequest) { List nodeInfoList = this.nodeRefToNodeInfo(nodeInfoRequest, @@ -304,7 +312,7 @@ public ResponseEntity getAllInfoOfNodes(@RequestBody final NodeInfoReque ); return writeJsonResponse(nodeInfoList); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/ancestors") public ResponseEntity retrieveAncestors(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @@ -330,6 +338,7 @@ public ResponseEntity retrieveAncestors(@PathVariable String space, @Pat } } + @AlfrescoTransaction @PostMapping(value = "/v1/nodes") public ResponseEntity createNode(@RequestBody final CreateNodeOptions createNodeOptions) { try { @@ -360,7 +369,7 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions if (createNodeOptions.getType() != null) { type = new QName(createNodeOptions.getType()); } else if (createNodeOptions.getType() == null && createNodeOptions.getCopyFrom() != null) { - type = nodeService.getMetadata(copyFrom).type; + type = nodeService.getMetadata(copyFrom).getType(); } else { return ResponseEntity.status(HttpStatus.SC_BAD_REQUEST) .body("Please provide parameter \"type\" when creating a new node"); @@ -392,6 +401,7 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions } } + @AlfrescoTransaction @PutMapping(value = "/v1/nodes/{space}/{store}/{guid}/parent") public ResponseEntity setParent(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid, @RequestBody ChangeParentOptions location) { @@ -410,7 +420,7 @@ public ResponseEntity setParent(@PathVariable final String space, @Path fileExistsException.getName()); } } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/comments") public ResponseEntity getComments(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestParam(defaultValue = "0") int skipcount, @@ -428,6 +438,7 @@ public ResponseEntity getComments(@PathVariable String space, @PathVariable S return writeNotAuthorizedResponse(new AccessDeniedException(target.getValue())); } + @AlfrescoTransaction @PostMapping(value = "/v1/nodes/{space}/{store}/{guid}/comments") public ResponseEntity addComment(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestBody final Comment newComment) { @@ -438,7 +449,7 @@ public ResponseEntity addComment(@PathVariable String space, @PathVariable St Comment responseComment = commentService.addNewComment(target, newComment.getContent()); return writeJsonResponse(responseComment); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/comments/{space}/{store}/{guid}") public ResponseEntity getComment(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -454,6 +465,7 @@ public ResponseEntity getComment(@PathVariable String space, @PathVariable St } } + @AlfrescoTransaction @PutMapping(value = "/v1/comments/{space}/{store}/{guid}") public ResponseEntity updateComment(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestBody final Comment newComment) { @@ -465,6 +477,7 @@ public ResponseEntity updateComment(@PathVariable String space, @PathVariable return writeJsonResponse(updatedComment); } + @AlfrescoTransaction @DeleteMapping(value = "/v1/comments/{space}/{store}/{guid}") public ResponseEntity deleteComment(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -475,7 +488,7 @@ public ResponseEntity deleteComment(@PathVariable String space, @PathVariable commentService.deleteComment(targetComment); return writeJsonResponse(String.format("Comment %s deleted", targetComment)); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/content") public ResponseEntity getContent(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { final NodeRef nodeRef = this.createNodeRef(space, store, guid); @@ -487,6 +500,7 @@ public ResponseEntity getContent(@PathVariable String space, @PathVariable St .body(new InputStreamResource(contentInputStream.getInputStream())); } + @AlfrescoTransaction @PutMapping(value = "/v1/nodes/{space}/{store}/{guid}/content") public ResponseEntity setContent(@PathVariable String space, @PathVariable String store, @PathVariable String guid, @RequestPart final MultipartFile file) { @@ -501,7 +515,7 @@ public ResponseEntity setContent(@PathVariable String space, @PathVariable return ResponseEntity.ok().build(); } - + @AlfrescoTransaction @DeleteMapping(value = "/v1/nodes/{space}/{store}/{guid}/content") public ResponseEntity deleteContent(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -514,7 +528,7 @@ public ResponseEntity deleteContent(@PathVariable String space, @PathVaria return ResponseEntity.ok().build(); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/exists") public ResponseEntity exists(@PathVariable String space, @PathVariable String store, @PathVariable String guid) { @@ -525,7 +539,7 @@ public ResponseEntity exists(@PathVariable String space, @PathVariable ); } - + @AlfrescoTransaction @PostMapping(value = "/v1/nodes/upload") public ResponseEntity uploadNode( @RequestParam(required = false) String type, diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java index 2e54e488..4ff512af 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/people/PeopleWebscript1.java @@ -1,11 +1,10 @@ package eu.xenit.apix.rest.v1.people; import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.people.IPeopleService; -import eu.xenit.apix.people.Person; import eu.xenit.apix.rest.v1.ApixV1Webscript; -import java.util.NoSuchElementException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; @@ -14,8 +13,10 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.util.NoSuchElementException; + @AlfrescoAuthentication(AuthenticationType.USER) -@RestController("eu.xenit.apix.rest.v1.people.PeopleWebscript") +@RestController public class PeopleWebscript1 extends ApixV1Webscript { private static final Logger logger = LoggerFactory.getLogger(PeopleWebscript1.class); @@ -25,10 +26,11 @@ public PeopleWebscript1(IPeopleService personService) { this.personService = personService; } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/people/{space}/{store}/{guid}") public ResponseEntity getPerson(@PathVariable final String space, - @PathVariable final String store, - @PathVariable final String guid) { + @PathVariable final String store, + @PathVariable final String guid) { logger.debug("Asked person with guid: {}", guid); try { return writeJsonResponse( @@ -38,19 +40,20 @@ public ResponseEntity getPerson(@PathVariable final String space, ); } catch (NoSuchElementException noSuchElementException) { return ResponseEntity.status(org.springframework.http.HttpStatus.NOT_FOUND) - .body(noSuchElementException.getMessage()); + .body(noSuchElementException.getMessage()); } catch (IllegalArgumentException illegalArgumentException) { return ResponseEntity.status(org.springframework.http.HttpStatus.BAD_REQUEST) .body(illegalArgumentException.getMessage()); } } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/people") public ResponseEntity getPersonViaUserName(@RequestParam final String userName) { logger.debug("Asked person with name: {}", userName); - try{ + try { return writeJsonResponse( - personService.GetPerson(userName) + personService.GetPerson(userName) ); } catch (NoSuchElementException noSuchElementException) { return ResponseEntity.status(org.springframework.http.HttpStatus.NOT_FOUND) diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java index 228ee19e..c1137461 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/properties/PropertiesWebScript1.java @@ -1,6 +1,7 @@ package eu.xenit.apix.rest.v1.properties; import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.data.QName; import eu.xenit.apix.dictionary.properties.IPropertyService; @@ -16,7 +17,7 @@ * @deprecated since Oct 2015, use DictionaryWebScript1 instead */ @AlfrescoAuthentication(AuthenticationType.USER) -@RestController("eu.xenit.apix.rest.v1.property.PropertiesWebScript1") +@RestController @Deprecated(since = "Deprecated since Oct 2015, use DictionaryWebScript1 instead") public class PropertiesWebScript1 extends ApixV1Webscript { @@ -26,11 +27,12 @@ public PropertiesWebScript1(IPropertyService propertyService) { this.propertyService = propertyService; } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/properties/{qname}") //Use qname with slash to avoid //https://stackoverflow.com/questions/13482020/encoded-slash-2f-with-spring-requestmapping-path-param-gives-http-400 public ResponseEntity getPropertyDefinition(@PathVariable final QName qname, - @RequestParam(required = false) QName qnameWithSlash) { + @RequestParam(required = false) QName qnameWithSlash) { QName apixQName = qnameWithSlash != null ? qnameWithSlash : qname; PropertyDefinition propDef = propertyService.GetPropertyDefinition(apixQName); if (propDef == null) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java index 8d0cb80c..4028fe1c 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/search/SearchWebScript1.java @@ -1,6 +1,7 @@ package eu.xenit.apix.rest.v1.search; import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.rest.v1.ApixV1Webscript; import eu.xenit.apix.search.ISearchService; @@ -11,7 +12,7 @@ import org.springframework.web.bind.annotation.RestController; @AlfrescoAuthentication(AuthenticationType.USER) -@RestController("eu.xenit.apix.rest.v1.search.SearchWebScriptV1") +@RestController public class SearchWebScript1 extends ApixV1Webscript { private final ISearchService service; @@ -20,6 +21,7 @@ public SearchWebScript1(ISearchService service) { this.service = service; } + @AlfrescoTransaction @PostMapping(value = "/v1/search") public ResponseEntity execute(@RequestBody final SearchQuery query) { try { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java index 8967a86d..7fd3a686 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/sites/SitesWebscript1.java @@ -21,7 +21,7 @@ import org.springframework.web.bind.annotation.RestController; @AlfrescoTransaction -@RestController("eu.xenit.apix.rest.v1.SitesWebscript") +@RestController public class SitesWebscript1 extends ApixV1Webscript { private static final Logger logger = LoggerFactory.getLogger(SitesWebscript1.class); @@ -45,7 +45,7 @@ public SitesWebscript1(INodeService nodeService, IPermissionService permissionSe this.siteService = siteService; this.serviceRegistry = serviceRegistry; } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/sites/mySites") public ResponseEntity> getMySites( @RequestParam(required = false, defaultValue = "false") Boolean retrieveMetadata, diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java index 5f02d19f..cd25bb1a 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/LogsWebscript.java @@ -1,6 +1,7 @@ package eu.xenit.apix.rest.v1.temp; import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.rest.v1.ApixV1Webscript; import java.io.File; @@ -13,7 +14,7 @@ import org.springframework.web.bind.annotation.RestController; -@RestController("eu.xenit.apix.rest.v1.temp.LogsWebscript") +@RestController public class LogsWebscript extends ApixV1Webscript { private final String logPath; @@ -21,7 +22,7 @@ public class LogsWebscript extends ApixV1Webscript { public LogsWebscript(Environment env) { logPath = env.resolvePlaceholders("$CATALINA_HOME/logs/catalina.out"); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/tmp/log", produces = { MediaType.TEXT_PLAIN_VALUE }) @AlfrescoAuthentication(AuthenticationType.ADMIN) public ResponseEntity showLog(@RequestParam(defaultValue = "200") int lines) throws IOException { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java index 42eb379c..ca274bd8 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/temp/WIPWebscript.java @@ -1,5 +1,6 @@ package eu.xenit.apix.rest.v1.temp; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.WIP.IWIPService; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.rest.v1.ApixV1Webscript; @@ -18,10 +19,11 @@ public WIPWebscript(IWIPService wipService) { this.wipService = wipService; } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/nodes/{space}/{store}/{guid}/content/previews/pdf") public ResponseEntity getPreviewPdf(@PathVariable String space, - @PathVariable String store, - @PathVariable String guid) { + @PathVariable String store, + @PathVariable String guid) { final NodeRef nodeRef = new NodeRef(space, store, guid); //TODO: from /searchapp/download return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java index c9c4544a..ee4d0228 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/translation/TranslationsWebscript1.java @@ -1,15 +1,17 @@ package eu.xenit.apix.rest.v1.translation; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.rest.v1.ApixV1Webscript; import eu.xenit.apix.translation.ITranslationService; import eu.xenit.apix.translation.Translations; -import java.util.Locale; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -@RestController("eu.xenit.apix.rest.v1.translation.TranslationsWebscript1") +import java.util.Locale; + +@RestController public class TranslationsWebscript1 extends ApixV1Webscript { private final ITranslationService translationService; @@ -18,6 +20,7 @@ public TranslationsWebscript1(ITranslationService translationService) { this.translationService = translationService; } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/translations/{locale}/checksum") public ResponseEntity getChecksum(@PathVariable final String locale) { Locale language = Locale.forLanguageTag(locale); @@ -26,6 +29,7 @@ public ResponseEntity getChecksum(@PathVariable final Strin return writeJsonResponse(checksumObj); } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/translations/{locale}") public ResponseEntity getTranslations(@PathVariable final String locale) { Locale language = Locale.forLanguageTag(locale); diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java index 72733e55..1c3738bd 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/versionhistory/VersionHistoryWebScript1.java @@ -1,6 +1,7 @@ package eu.xenit.apix.rest.v1.versionhistory; import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.data.QName; import eu.xenit.apix.rest.v1.ApixV1Webscript; @@ -22,7 +23,7 @@ import org.springframework.web.bind.annotation.RestController; @AlfrescoAuthentication(AuthenticationType.USER) -@RestController("eu.xenit.apix.rest.v1.versionhistory.VersionHistoryWebScript1") +@RestController public class VersionHistoryWebScript1 extends ApixV1Webscript { private static final Logger logger = LoggerFactory.getLogger(VersionHistoryWebScript1.class); @@ -39,7 +40,7 @@ public class VersionHistoryWebScript1 extends ApixV1Webscript { public VersionHistoryWebScript1(IVersionHistoryService versionHistoryService) { this.versionHistoryService = versionHistoryService; } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/versions") public ResponseEntity getVersionHistory(@PathVariable final String space, @PathVariable final String store, @@ -49,7 +50,7 @@ public ResponseEntity getVersionHistory(@PathVariable final Stri versionHistoryService.GetVersionHistory(createNodeRef(space, store, guid)) ); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/root") public ResponseEntity getVersionHistoryRoot(@PathVariable final String space, @PathVariable final String store, @@ -58,7 +59,7 @@ public ResponseEntity getVersionHistoryRoot(@PathVariable final String versionHistoryService.getRootVersion(createNodeRef(space, store, guid)) ); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/head") public ResponseEntity getVersionHistoryHead(@PathVariable final String space, @PathVariable final String store, @@ -68,6 +69,7 @@ public ResponseEntity getVersionHistoryHead(@PathVariable final String ); } + @AlfrescoTransaction @DeleteMapping(value = "/v1/versionhistory/{space}/{store}/{guid}") //No method available to disable versioning. deleting will merely reset version history, // starting a new history upon a new version change @@ -77,6 +79,8 @@ public ResponseEntity deleteVersionHistory(@PathVariable final String space, versionHistoryService.deleteVersionHistory(createNodeRef(space, store, guid)); return ResponseEntity.ok().build(); } + + @AlfrescoTransaction @PutMapping(value = "/v1/versionhistory/{space}/{store}/{guid}") public ResponseEntity setVersionHistory(@PathVariable final String space, @PathVariable final String store, @@ -98,6 +102,7 @@ public ResponseEntity setVersionHistory(@PathVariable final String space, return ResponseEntity.ok().build(); } + @AlfrescoTransaction @PostMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/versions/{label}/revert") public ResponseEntity revertVersionHistory(@PathVariable final String space, @PathVariable final String store, @@ -107,6 +112,7 @@ public ResponseEntity revertVersionHistory(@PathVariable final String space, return ResponseEntity.ok().build(); } + @AlfrescoTransaction @DeleteMapping(value = "/v1/versionhistory/{space}/{store}/{guid}/versions/{label}") public ResponseEntity deleteVersion(@PathVariable final String space, @PathVariable final String store, diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java index 536b4d81..31ab6b5b 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/workingcopies/WorkingcopiesWebscript1.java @@ -1,5 +1,6 @@ package eu.xenit.apix.rest.v1.workingcopies; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.node.INodeService; import eu.xenit.apix.rest.v1.ApixV1Webscript; @@ -12,7 +13,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -@RestController("eu.xenit.apix.rest.v1.WorkingcopiesWebscript1") +@RestController public class WorkingcopiesWebscript1 extends ApixV1Webscript { private final INodeService nodeService; @@ -21,6 +22,7 @@ public WorkingcopiesWebscript1(INodeService nodeService) { this.nodeService = nodeService; } + @AlfrescoTransaction @PostMapping(value = "/v1/workingcopies") public ResponseEntity createWorkingcopy(@RequestBody CheckoutBody checkoutBody) { final NodeRef originalRef = checkoutBody.getOriginal(); @@ -38,6 +40,7 @@ public ResponseEntity createWorkingcopy(@RequestBody CheckoutBody checkoutBod return respondDoesNotExist(destinationRef); } + @AlfrescoTransaction @PostMapping(value = "/v1/workingcopies/{space}/{store}/{guid}/checkin") public ResponseEntity checkinWorkingcopy(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid, @@ -50,6 +53,7 @@ public ResponseEntity checkinWorkingcopy(@PathVariable final String space, @P return respondDoesNotExist(nodeRef); } + @AlfrescoTransaction @DeleteMapping(value = "/v1/workingcopies/{space}/{store}/{guid}") public ResponseEntity cancelWorkingcopy(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid) { @@ -60,7 +64,7 @@ public ResponseEntity cancelWorkingcopy(@PathVariable final String space, @Pa } return respondDoesNotExist(workingCopyRef); } - + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v1/workingcopies/{space}/{store}/{guid}/original") public ResponseEntity getWorkingCopySource(@PathVariable final String space, @PathVariable final String store, @PathVariable final String guid) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java index d30b0cd8..2cc6d795 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/groups/GroupsWebscript.java @@ -1,14 +1,12 @@ package eu.xenit.apix.rest.v2.groups; import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.groups.Group; import eu.xenit.apix.people.IPeopleService; import eu.xenit.apix.people.Person; import eu.xenit.apix.rest.v2.ApixV2Webscript; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,9 +18,13 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + @AlfrescoAuthentication(AuthenticationType.USER) -@RestController("eu.xenit.apix.rest.v2.groups.GroupsWebscript") +@RestController public class GroupsWebscript extends ApixV2Webscript { private static final Logger logger = LoggerFactory.getLogger(GroupsWebscript.class); @@ -32,11 +34,13 @@ public GroupsWebscript(IPeopleService personService) { this.personService = personService; } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v2/groups") public ResponseEntity> GetAllGroups() { return writeJsonResponse(personService.GetGroups()); } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v2/groups/{name}/people") public ResponseEntity GetPeopleOfGroup(@PathVariable final String name, @RequestParam(required = false) Boolean immediate) { @@ -50,9 +54,10 @@ public ResponseEntity GetPeopleOfGroup(@PathVariable final String name, return ResponseEntity.ok(people); } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v2/groups/{name}/groups") public ResponseEntity GetGroupsOfGroup(@PathVariable final String name, - @RequestParam(required = false) Boolean immediate) { + @RequestParam(required = false) Boolean immediate) { if (immediate == null) { immediate = false; } @@ -64,9 +69,10 @@ public ResponseEntity GetGroupsOfGroup(@PathVariable final String name, return writeJsonResponse(groups); } + @AlfrescoTransaction @PutMapping(value = "/v2/groups/{name}/people") public ResponseEntity SetPeopleInGroup(@PathVariable final String name, - @RequestBody SetUsersInGroupOptions options) { + @RequestBody SetUsersInGroupOptions options) { // We want to replace all of the users in group {name} by a new list of users // We're going to avoid unlinking and re-linking the same user, because iterating over the list to check for // duplicates is going to be cheaper than unnecessarily invoking all of Alfresco's internal safety checking @@ -88,10 +94,10 @@ public ResponseEntity SetPeopleInGroup(@PathVariable final String name, return ResponseEntity.ok().build(); } - + @AlfrescoTransaction @PutMapping(value = "/v2/groups/{name}/groups") public ResponseEntity SetGroupsOfGroup(@PathVariable final String name, - @RequestBody SetSubgroupOptions options) { + @RequestBody SetSubgroupOptions options) { // We want to replace all of the subgroups of {name} by a new list of subgroups // We're going to avoid unlinking and re-linking the same group, because iterating over the list to check for // duplicates is going to be cheaper than unnecessarily invoking all of Alfresco's internal safety checking diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java index 8740e68a..9f0effbe 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/nodes/NodesWebscriptV2.java @@ -1,6 +1,7 @@ package eu.xenit.apix.rest.v2.nodes; import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.data.QName; import eu.xenit.apix.filefolder.IFileFolderService; @@ -29,7 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger; @AlfrescoAuthentication -@RestController("eu.xenit.apix.rest.v2.NodesWebscript") +@RestController public class NodesWebscriptV2 extends ApixV2Webscript { private static final Logger logger = LoggerFactory.getLogger(NodesWebscriptV2.class); @@ -50,6 +51,7 @@ public NodesWebscriptV2(INodeService nodeService, IPermissionService permissionS this.serviceRegistry = serviceRegistry; } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v2/nodes/{space}/{store}/{guid}") public ResponseEntity getAllInfo(@PathVariable String space, @PathVariable String store, @@ -62,6 +64,7 @@ public ResponseEntity getAllInfo(@PathVariable String space, return writeJsonResponse(nodeInfo); } + @AlfrescoTransaction @PostMapping(value = "/v2/nodes/nodeInfo") public ResponseEntity> getAllInfos(@RequestBody final NodeInfoRequest nodeInfoRequest) throws JSONException { List nodeInfoList = this.nodeRefToNodeInfo( @@ -72,6 +75,7 @@ public ResponseEntity> getAllInfos(@RequestBody final NodeInfoReq return writeJsonResponse(nodeInfoList); } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v2/nodes/{space}/{store}/{guid}/permissions") public ResponseEntity> getPermissions(@PathVariable String space, @PathVariable String store, @@ -82,6 +86,7 @@ public ResponseEntity> getPermissions(@PathVariable ); } + @AlfrescoTransaction @PostMapping(value = "/v2/nodes") public ResponseEntity createNode(@RequestBody final CreateNodeOptions createNodeOptions) { final StringBuilder errorMessage = new StringBuilder(); @@ -117,7 +122,7 @@ public ResponseEntity createNode(@RequestBody final CreateNodeOptions createN if (createNodeOptions.getType() != null) { type = new QName(createNodeOptions.getType()); } else if (createNodeOptions.getCopyFrom() != null) { - type = nodeService.getMetadata(copyFrom).type; + type = nodeService.getMetadata(copyFrom).getType(); } else { errorCode.addAndGet(HttpStatus.SC_BAD_REQUEST); errorMessage.append( diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java index a62b9df5..5bebba5c 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v2/people/PeopleWebscript.java @@ -1,14 +1,11 @@ package eu.xenit.apix.rest.v2.people; import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; +import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; import eu.xenit.apix.people.IPeopleService; import eu.xenit.apix.people.Person; import eu.xenit.apix.rest.v2.ApixV2Webscript; -import java.util.ArrayList; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; @@ -16,8 +13,13 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Set; + @AlfrescoAuthentication(AuthenticationType.USER) -@RestController("eu.xenit.apix.rest.v2.people.PeopleWebscript") +@RestController public class PeopleWebscript extends ApixV2Webscript { private static final Logger logger = LoggerFactory.getLogger(PeopleWebscript.class); @@ -27,10 +29,11 @@ public PeopleWebscript(IPeopleService personService) { this.personService = personService; } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v2/people/id/{space}/{store}/{guid}") public ResponseEntity getPerson(@PathVariable final String space, - @PathVariable final String store, - @PathVariable final String guid) { + @PathVariable final String store, + @PathVariable final String guid) { logger.debug("Asked person with guid: {}", guid); try { return writeJsonResponse( @@ -45,22 +48,25 @@ public ResponseEntity getPerson(@PathVariable final String space, } } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v2/people") public ResponseEntity> getAllPeople() { return writeJsonResponse(personService.GetPeople()); } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v2/people/-me-") public ResponseEntity getPersonCurrentUser() { return getPersonWithName("-me-"); } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v2/people/{name}") public ResponseEntity getPersonWithName(@PathVariable final String name) { logger.debug("Asked person with name: {}", name); - try{ + try { return writeJsonResponse( - personService.GetPerson(name) + personService.GetPerson(name) ); } catch (NoSuchElementException noSuchElementException) { return ResponseEntity.status(org.springframework.http.HttpStatus.NOT_FOUND) @@ -71,6 +77,7 @@ public ResponseEntity getPersonWithName(@PathVariable final String name) { } } + @AlfrescoTransaction(readOnly = true) @GetMapping(value = "/v2/ people/containergroups/{name}") public ResponseEntity> getContainerGroupsOf(@PathVariable final String name) { logger.debug("Asked containergroups for person with name: {}", name); diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.delete.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.delete.desc.xml index cb177ee8..558adb88 100644 --- a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.delete.desc.xml +++ b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.delete.desc.xml @@ -2,7 +2,7 @@ Alfred API Delete /apix/{path} user - required + none diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.get.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.get.desc.xml index b4f8815a..4fe7cea4 100644 --- a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.get.desc.xml +++ b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.get.desc.xml @@ -2,7 +2,7 @@ Alfred API Get /apix/{path} user - required + none diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.post.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.post.desc.xml index d5b0be69..4bc20aa2 100644 --- a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.post.desc.xml +++ b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.post.desc.xml @@ -2,7 +2,7 @@ Alfred API Post /apix/{path} user - required + none diff --git a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.put.desc.xml b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.put.desc.xml index cc207c3c..d7e5611d 100644 --- a/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.put.desc.xml +++ b/apix-rest-v1/src/main/resources/alfresco/extension/templates/webscripts/alfred/api.put.desc.xml @@ -2,7 +2,7 @@ Alfred API Put /apix/{path} user - required + none From ecedb8adb75478f6d527215a712fef7557636174 Mon Sep 17 00:00:00 2001 From: Hechmi Dammak Date: Fri, 28 Apr 2023 09:26:29 +0100 Subject: [PATCH 44/90] ALFREDAPI-518 remove artifactory and use alfresco nexus --- .github/workflows/ci.yml | 4 ++-- build.gradle | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d0245c6..398f5e68 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,8 +3,8 @@ on: push: workflow_dispatch: env: - XENIT_ARTIFACTORY_USERNAME: ${{ secrets.XENIT_ARTIFACTORY_USERNAME }} - XENIT_ARTIFACTORY_PASSWORD: ${{ secrets.XENIT_ARTIFACTORY_PASSWORD }} + ALFRESCO_NEXUS_USERNAME: ${{ secrets.ALFRESCO_NEXUS_USERNAME }} + ALFRESCO_NEXUS_PASSWORD: ${{ secrets.ALFRESCO_NEXUS_PASSWORD }} jobs: test: runs-on: ubuntu-latest diff --git a/build.gradle b/build.gradle index 947c549d..2c2a5eb0 100644 --- a/build.gradle +++ b/build.gradle @@ -41,11 +41,10 @@ subprojects { // This private repository provides Xenit with Alfresco enterprise artefacts. // External developers should replace it with their own library repository. maven { - name 'Xenit artifactory libs-release' - url 'https://artifactory.xenit.eu/artifactory/libs-release' + url 'https://artifacts.alfresco.com/nexus/content/groups/private' credentials { - username System.env.XENIT_ARTIFACTORY_USERNAME ?: property("eu.xenit.artifactory.username") - password System.env.XENIT_ARTIFACTORY_PASSWORD ?: property("eu.xenit.artifactory.password") + username System.env.ALFRESCO_NEXUS_USERNAME ?: property("org.alfresco.maven.nexus.username") + password System.env.ALFRESCO_NEXUS_PASSWORD ?: property("org.alfresco.maven.nexus.password") } } } From 27327174b5e93bad3c3408af840d8eff266de8bc Mon Sep 17 00:00:00 2001 From: Hechmi Dammak Date: Fri, 28 Apr 2023 10:37:34 +0100 Subject: [PATCH 45/90] ALFREDAPI-518 fix publishing --- .github/workflows/ci.yml | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 398f5e68..8e4b033a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,7 +65,7 @@ jobs: name: test-result-${{ matrix.alfresco_version }} path: /home/runner/work/**/build/reports retention-days: 2 - publish: + publish-interface: needs: [ test, integration-test ] runs-on: ubuntu-latest if: ${{ startsWith(github.ref, 'refs/heads/master') || startsWith(github.ref, 'refs/heads/release') }} @@ -88,4 +88,30 @@ jobs: arguments: >- --info -PsigningKeyId=DF8285F0 :apix-interface:publish - :alfresco:publish + publish-impl: + needs: [ test, integration-test ] + runs-on: ubuntu-latest + if: ${{ startsWith(github.ref, 'refs/heads/master') || startsWith(github.ref, 'refs/heads/release') }} + strategy: + fail-fast: false + matrix: + alfresco_version: [ 62, 70, 71, 72, 73 ] + steps: + - name: Check out + uses: actions/checkout@v3 + - name: Set up JDK + uses: actions/setup-java@v3 + with: + java-version: 11 + distribution: temurin + - name: Publish + uses: gradle/gradle-build-action@v2.3.0 + env: + ORG_GRADLE_PROJECT_signingKey: ${{ secrets.MAVEN_CENTRAL_GPG_KEY }} + ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.MAVEN_CENTRAL_GPG_PASSWORD }} + ORG_GRADLE_PROJECT_sonatype_username: ${{ secrets.SONATYPE_S01_USERNAME }} + ORG_GRADLE_PROJECT_sonatype_password: ${{ secrets.SONATYPE_S01_PASSWORD }} + with: + arguments: >- + --info -PsigningKeyId=DF8285F0 + :alfresco:${{ matrix.alfresco_version }}:publish \ No newline at end of file From 8b7ace60a27d0dfd660c604b16d2245ef5e21378 Mon Sep 17 00:00:00 2001 From: Robrecht Vanhuysse Date: Fri, 16 Jun 2023 15:01:39 +0200 Subject: [PATCH 46/90] ALFREDAPI-520 enforce charencoding for clean response in bulk endpoint --- CHANGELOG.md | 5 ++--- .../main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java | 6 +++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7118de22..c59cff96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,16 @@ # Alfred API - Changelog -## 4.0.1 (yyyy-mm-dd) +## 4.0.2 (yyyy-mm-dd) ### Added ### Changed - ### Fixed +* [ALFREDAPI-520](https://xenitsupport.jira.com/browse/ALFREDAPI-520): Enforce encoding on json responses to guarantee clean response in bulk webscript ### Removed - ## 4.0.1 (unreleased) ### Added diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java index a2086e4e..ca52378a 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java @@ -12,8 +12,10 @@ import eu.xenit.apix.permissions.PermissionValue; import eu.xenit.apix.rest.v1.nodes.NodeInfo; import eu.xenit.apix.rest.v1.nodes.NodeInfoRequest; +import java.nio.charset.StandardCharsets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import java.util.ArrayList; @@ -26,7 +28,9 @@ public class ApixV1Webscript { private static final Logger logger = LoggerFactory.getLogger(ApixV1Webscript.class); protected ResponseEntity writeJsonResponse(T object) { - return ResponseEntity.ok(object); + return ResponseEntity.ok() + .contentType(new MediaType("application", "json", StandardCharsets.UTF_8)) + .body(object); } protected NodeRef createNodeRef(String space, String store, String guid) { From eb595551fcfa6fa3245a2b5177aa56ac08a5cb74 Mon Sep 17 00:00:00 2001 From: Robrecht Vanhuysse Date: Tue, 20 Jun 2023 13:41:39 +0200 Subject: [PATCH 47/90] ALFREDAPI-520 specific fix in bulk webscript implementation --- CHANGELOG.md | 2 +- .../main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java | 4 +--- .../java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java | 7 +++++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c59cff96..9a64e98a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ ### Changed ### Fixed -* [ALFREDAPI-520](https://xenitsupport.jira.com/browse/ALFREDAPI-520): Enforce encoding on json responses to guarantee clean response in bulk webscript +* [ALFREDAPI-520](https://xenitsupport.jira.com/browse/ALFREDAPI-520): Enforce encoding on bulk json responses to guarantee clean text ### Removed diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java index ca52378a..b26d7ab9 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java @@ -28,9 +28,7 @@ public class ApixV1Webscript { private static final Logger logger = LoggerFactory.getLogger(ApixV1Webscript.class); protected ResponseEntity writeJsonResponse(T object) { - return ResponseEntity.ok() - .contentType(new MediaType("application", "json", StandardCharsets.UTF_8)) - .body(object); + return ResponseEntity.ok(object); } protected NodeRef createNodeRef(String space, String store, String guid) { diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java index 0a8569f7..ae4919d1 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/BulkWebscript1.java @@ -9,6 +9,7 @@ import eu.xenit.apix.rest.v1.bulk.request.BulkRequest; import eu.xenit.apix.rest.v1.bulk.request.IntermediateRequest; import eu.xenit.apix.rest.v1.bulk.response.IntermediateResponse; +import java.nio.charset.StandardCharsets; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.ServiceRegistry; import org.slf4j.Logger; @@ -69,6 +70,12 @@ public ResponseEntity> bulk(@RequestBody final BulkRequest[] final IntermediateRequest intermediateRequest = new IntermediateRequest(wsReq, bulkHttpServletRequest); final IntermediateResponse intermediateResponse = new IntermediateResponse(); + // ALFREDAPI-520: Due to the bulk script circumventing the spring framework config + // through the alfresco-mvc dispatcher servlet, the encoding of the response can be mangled. + // Setting it here avoids this issue. + // This is not considered breaking since the original implementation did not have a mechanism for the client + // to request certain encodings. + intermediateResponse.setCharacterEncoding(StandardCharsets.UTF_8.toString()); final WebScriptServletResponse webScriptServletResponse = new WebScriptServletResponse(wsReq.getRuntime(), intermediateResponse); From 5c41c8315410d18d31e9cfc7c505f0fb9db0def8 Mon Sep 17 00:00:00 2001 From: Robrecht Vanhuysse Date: Wed, 21 Jun 2023 11:38:18 +0200 Subject: [PATCH 48/90] ALFREDAPI-520 remove obsolete imports --- .../src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java index b26d7ab9..a2086e4e 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/ApixV1Webscript.java @@ -12,10 +12,8 @@ import eu.xenit.apix.permissions.PermissionValue; import eu.xenit.apix.rest.v1.nodes.NodeInfo; import eu.xenit.apix.rest.v1.nodes.NodeInfoRequest; -import java.nio.charset.StandardCharsets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import java.util.ArrayList; From 1d41a1cde15361d12b41b400d1d47ad8323c584b Mon Sep 17 00:00:00 2001 From: Benjamin Van der Smissen Date: Thu, 22 Jun 2023 16:14:13 +0200 Subject: [PATCH 49/90] ALFREDAPI-521-Bump-version [Update] version 4.0.2 --- CHANGELOG.md | 9 +++++++++ build.gradle | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9b22ff1..4af7afaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ # Alfred API - Changelog +## 4.0.2 (unreleased) + + +### Added +### Changed +### Fixed +### Removed + + ## 4.0.1 (2023-06-13) This release removes swaggerui_5x from alfred-api artifact and changes generation of Snapshot qualifier to comform to maven format. diff --git a/build.gradle b/build.gradle index 4f4cf836..9a98bb67 100644 --- a/build.gradle +++ b/build.gradle @@ -37,7 +37,7 @@ buildscript { } ext { - versionWithoutQualifier = '4.0.1' + versionWithoutQualifier = '4.0.2' jackson_version = '2.8.3' swagger_version = "1.5.7" From dcbf2d950f175682672c7a3cdf8163c95b335488 Mon Sep 17 00:00:00 2001 From: Hechmi Dammak Date: Mon, 26 Jun 2023 13:25:42 +0100 Subject: [PATCH 50/90] ALFREDAPI-523 fix configuration endpoint --- .../apix/rest/v1/tests/ConfigurationTest.java | 80 +++++++------------ .../ConfigurationWebscript1.java | 63 ++++++++------- 2 files changed, 63 insertions(+), 80 deletions(-) diff --git a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java index 22d3d0e2..c6f3ef02 100644 --- a/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java +++ b/apix-integrationtests/alfresco/src/main/java/eu/xenit/apix/rest/v1/tests/ConfigurationTest.java @@ -1,17 +1,10 @@ package eu.xenit.apix.rest.v1.tests; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - import eu.xenit.apix.content.IContentService; import eu.xenit.apix.data.NodeRef; import eu.xenit.apix.data.QName; import eu.xenit.apix.filefolder.IFileFolderService; import eu.xenit.apix.node.INodeService; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.net.URLEncoder; import org.alfresco.model.ContentModel; import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -37,12 +30,21 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.MediaType; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URLEncoder; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.springframework.http.HttpHeaders.CONTENT_TYPE; + /** * Created by kenneth on 14.03.16. */ public class ConfigurationTest extends RestV1BaseTest { - private final static Logger logger = LoggerFactory.getLogger(ConfigurationTest.class); + private static final Logger logger = LoggerFactory.getLogger(ConfigurationTest.class); @Autowired @Qualifier("FileFolderService") @@ -125,20 +127,7 @@ private String makeBasePath() { @Test public void testConfigurationGet() throws IOException, JSONException { - String requestUrl = makeBasePath(); - - HttpResponse response = Request - .Get(requestUrl) - .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .execute() - .returnResponse(); - - assertEquals(200, response.getStatusLine().getStatusCode()); - - JSONObject jsonObject = new JSONObject(EntityUtils.toString(response.getEntity())); - - JSONArray jsonFiles = jsonObject.getJSONArray("files"); - + JSONArray jsonFiles = callConfiguration(makeBasePath()); assertEquals(4, jsonFiles.length()); for (int i = 0; i < jsonFiles.length(); i++) { @@ -157,21 +146,20 @@ public void testConfigurationGet() throws IOException, JSONException { } @Test - public void testConfigurationGetFields() throws IOException, JSONException { - String requestUrl = makeBasePath() + "&fields=nodeRef,path,metadata,parsedContent"; - + public void testConfigurationGetJS() throws IOException, JSONException { HttpResponse response = Request - .Get(requestUrl) - .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .Get(makeBasePath()) + .addHeader(HttpHeaders.ACCEPT, "application/js") .execute() .returnResponse(); - assertEquals(200, response.getStatusLine().getStatusCode()); + assertEquals("application/js", response.getFirstHeader(CONTENT_TYPE).getValue()); + } - JSONObject jsonObject = new JSONObject(EntityUtils.toString(response.getEntity())); - - JSONArray jsonFiles = jsonObject.getJSONArray("files"); - + @Test + public void testConfigurationGetFields() throws IOException, JSONException { + String requestUrl = makeBasePath() + "&fields=nodeRef,path,metadata,parsedContent"; + JSONArray jsonFiles = callConfiguration(requestUrl); assertEquals(4, jsonFiles.length()); for (int i = 0; i < jsonFiles.length(); i++) { @@ -207,10 +195,7 @@ public void testConfigurationGetFields() throws IOException, JSONException { } - @Test - public void testConfigurationFilterFields() throws IOException, JSONException { - String requestUrl = makeBasePath() + "&filter.name=" + URLEncoder.encode("\\.yaml$", "UTF-8"); - + private JSONArray callConfiguration(String requestUrl) throws IOException { HttpResponse response = Request .Get(requestUrl) .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) @@ -218,11 +203,19 @@ public void testConfigurationFilterFields() throws IOException, JSONException { .returnResponse(); assertEquals(200, response.getStatusLine().getStatusCode()); + assertEquals("application/json", response.getFirstHeader(CONTENT_TYPE).getValue()); JSONObject jsonObject = new JSONObject(EntityUtils.toString(response.getEntity())); JSONArray jsonFiles = jsonObject.getJSONArray("files"); + return jsonFiles; + } + + @Test + public void testConfigurationFilterFields() throws IOException, JSONException { + String requestUrl = makeBasePath() + "&filter.name=" + URLEncoder.encode("\\.yaml$", "UTF-8"); + JSONArray jsonFiles = callConfiguration(requestUrl); assertEquals(2, jsonFiles.length()); for (int i = 0; i < jsonFiles.length(); i++) { JSONObject jsonFile = jsonFiles.getJSONObject(i); @@ -235,19 +228,7 @@ public void testConfigurationFilterFields() throws IOException, JSONException { @Test public void testConfigurationSubdirectory() throws IOException, JSONException { String requestUrl = makeBasePath() + "/subFolder"; - - HttpResponse response = Request - .Get(requestUrl) - .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .execute() - .returnResponse(); - - assertEquals(200, response.getStatusLine().getStatusCode()); - - JSONObject jsonObject = new JSONObject(EntityUtils.toString(response.getEntity())); - - JSONArray jsonFiles = jsonObject.getJSONArray("files"); - + JSONArray jsonFiles = callConfiguration(requestUrl); assertEquals(1, jsonFiles.length()); for (int i = 0; i < jsonFiles.length(); i++) { JSONObject jsonFile = jsonFiles.getJSONObject(i); @@ -267,7 +248,6 @@ public void cleanUp() { removeTestNode(new org.alfresco.service.cmr.repository.NodeRef(testFolder.toString())); } catch (RuntimeException ex) { logger.debug("Did not need to remove mainTestFolder because it did not exist"); - //ex.printStackTrace(); } return null; }; diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java index 75f361ff..ca9377de 100644 --- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java +++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java @@ -6,25 +6,28 @@ import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication; import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction; import com.gradecak.alfresco.mvc.annotation.AuthenticationType; +import com.gradecak.alfresco.mvc.webscript.DispatcherWebscript; import eu.xenit.apix.configuration.ConfigurationFileFlags; import eu.xenit.apix.configuration.ConfigurationService; import eu.xenit.apix.configuration.Configurations; import eu.xenit.apix.rest.v1.ApixV1Webscript; - -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.lang.Nullable; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + @AlfrescoAuthentication(AuthenticationType.USER) @RestController public class ConfigurationWebscript1 extends ApixV1Webscript { @@ -45,13 +48,14 @@ public ConfigurationWebscript1( } @AlfrescoTransaction(readOnly = true) - @GetMapping(value = "/v1/configuration", consumes = {"application/js"}, produces = {"application/js"}) + @GetMapping(value = "/v1/configuration", produces = {"application/js", MediaType.APPLICATION_JSON_VALUE}) public ResponseEntity getJsConfigurationFiles( @RequestParam(defaultValue = "content,nodeRef", required = false) String[] fields, @RequestParam String searchDirectory, @RequestParam(value = "filter.name", required = false) String nameFilter, - @RequestParam(required = false) String callback + @RequestParam(required = false) String callback, final HttpServletRequest req ) throws IOException { + final WebScriptRequest wsReq = ((DispatcherWebscript.WebscriptRequestWrapper) req).getWebScriptServletRequest(); List fieldsList = Arrays.asList(fields); ConfigurationFileFlags configurationFileFlags = new ConfigurationFileFlags( fieldsList.contains("content"), @@ -61,32 +65,31 @@ public ResponseEntity getJsConfigurationFiles( fieldsList.contains("nodeRef")); Configurations configurations = configurationService .getConfigurationFiles(searchDirectory, nameFilter, configurationFileFlags); + if ("js".equalsIgnoreCase(wsReq.getFormat()) || + "js".equalsIgnoreCase( + getAcceptSubType( + req.getHeader("Accept")))) { + return ResponseEntity.ok() + .contentType(new MediaType("application", "js")) + .body( + String.format("%s(%s)", callback, + mapper.writeValueAsString(configurations))); + } return ResponseEntity.ok() - .body( - String.format("%s(%s)", callback, - mapper.writeValueAsString(configurations))); + .contentType(MediaType.APPLICATION_JSON) + .body(configurations); } - @AlfrescoTransaction(readOnly = true) - @GetMapping(value = "/v1/configuration" , - consumes = {MediaType.APPLICATION_JSON_VALUE}, - produces = {MediaType.APPLICATION_JSON_VALUE}) - public ResponseEntity getConfigurationFiles( - @RequestParam(defaultValue = "content,nodeRef", required = false) String[] fields, - @RequestParam String searchDirectory, - @RequestParam(value = "filter.name", required = false) String nameFilter - ) throws IOException { - List fieldsList = Arrays.asList(fields); - ConfigurationFileFlags configurationFileFlags = new ConfigurationFileFlags( - fieldsList.contains("content"), - fieldsList.contains("path"), - fieldsList.contains("parsedContent"), - fieldsList.contains("metadata"), - fieldsList.contains("nodeRef")); - Configurations configurations = configurationService - .getConfigurationFiles(searchDirectory, nameFilter, configurationFileFlags); - return ResponseEntity.ok() - .body(configurations); + @Nullable + private static String getAcceptSubType(String accept) { + String acceptSubType = null; + if (accept != null) { + String[] acceptSplit = accept.split("/"); + if (acceptSplit.length > 1) { + acceptSubType = acceptSplit[1]; + } + } + return acceptSubType; } @ExceptionHandler(IllegalArgumentException.class) From 7f79ad43c44fe709aeae347440c1f5d093eefb3d Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 28 Jun 2023 11:32:42 +0200 Subject: [PATCH 51/90] ALFREDAPI-524: Update README after MVC --- README.md | 33 ++++++--------------------------- apix-docker/build.gradle | 2 +- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 2baa44e6..1690e521 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,6 @@ are not supported by the Alfresco Public API. ## Usage Full documentation can be found at the [project's documentation](https://docs.xenit.eu/alfred-api/stable-user/index.html). -## Installation - -### Pre-requisites -Alfred API requires **_Dynamic Extensions For Alfresco_**, version 2.0.1 or later. This module should be installed first. -Acquisition and installation instructions can be found [here](https://github.com/xenit-eu/dynamic-extensions-for-alfresco). - - ## Contributing ### Rules for pull requests @@ -49,12 +42,10 @@ Acquisition and installation instructions can be found [here](https://github.com * *apix-interface* builds the interface of Alfred API. This part is agnostic of the Alfresco version used. * *apix-rest-v1* builds the REST API of Alfred API. -* *apix-impl* builds the AMP which is the main deliverable for Alfred API. The AMP contains the JARs of -*apix-interface* and *apix-rest-v1*. - * The top directory also contains code shared over different Alfresco versions. - * *apix-impl/xx* contains all code per Alfresco version. It has a *src/java* folder - for code specific to that Alfresco version and a *src/java-shared code* for the code shared between - versions. This code is automatically symlinked from the *apix-impl* directory. +* *apix-impl* builds the Java code for each version of Alfresco. +* *alfresco* builds the AMP for each Alfresco version that is the main deliverable for Alfred API. The AMP contains + the JARs of *apix-interface* and *apix-rest-v1*. + * *alfresco/xx* contains the correct properties for each Alfresco version. * *apix-integrationtests* contains the integration tests for each Alfresco version. ### How to @@ -70,7 +61,7 @@ Where `VERSION` is e.g. `70`. #### Run integration tests ```bash -./gradlew :apix-integrationtests:test-${VERSION}:integrationTest +./gradlew :apix-integrationtests:alfresco:${VERSION}:integrationTest ``` Again, where `VERSION` is e.g. `70`. @@ -84,7 +75,7 @@ However, this starts (and afterwards stops) docker containers. This includes sta #### Run integration tests under debugger 1. Debugging settings are already added by `apix-docker/${VERSION}/debug-extension.docker-compose.yml`, including a -portmapping `8000:8000`. This file does not get loaded when running in Jenkins. +portmapping `8000:8000`. This file does not get loaded when running in CI. 2. Prepare your remote debugger in IntelliJ and set breakpoints where you want in your tests (or Alfred API code). 3. Run the integration tests (see section above). @@ -92,18 +83,6 @@ portmapping `8000:8000`. This file does not get loaded when running in Jenkins. Again, where `VERSION` is e.g. `70`. -#### Deploy code changes for development -In a development scenario, it is possible to upload code changes to a running alfresco through dynamic extensions. -This requires the running alfresco to already have an older or equal version of alfred-api installed, and -the use of the jar artifact instead of the amp to do the new install. -The JAR has the format `apix-impl-{ALFRESCO-VERSION}-{APIX-VERSION}.jar` and can be found under -`apix-impl/{ALFRESCO-VERSION}/build/libs/`, where `ALFRESCO-VERSION` is one of *(62|70|71|72|73)*. -The new installation can be done either through the DE web interface, or with the following gradle task. -```bash -./gradlew :apix-impl:apix-impl-{ALFRESCO-VERSION}:installBundle -Phost={ALFRESCO-HOST} -Pport={ALFRESCO-PORT} -``` -Where `VERSION` is e.g. `70` and here `PORT` is the port mapping of the *alfresco-core* container e.g. `32774`. - *Protip:* If you get tired of changing the port after every `docker-compose up`, you can temporarily put a fixed port in the *docker-compose.yml* of the version you are working with. (The rationale behind using variable ephemeral ports is that during parallel builds on Jenkins port clashes must be avoided.) diff --git a/apix-docker/build.gradle b/apix-docker/build.gradle index 11b03727..79c91f88 100644 --- a/apix-docker/build.gradle +++ b/apix-docker/build.gradle @@ -22,7 +22,7 @@ subprojects { dockerCompose { useComposeFiles = ['docker-compose.yml'] - // Don't use the dev compose file on Jenkins + // Don't use the dev compose file during CI builds if (!ci.isCi()) { // Allow the dev compose file to be deleted def extraComposeFile = 'debug-extension.docker-compose.yml' From 18821b139a8cee07b3b540da80032859c1f8dd02 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 28 Jun 2023 11:32:42 +0200 Subject: [PATCH 52/90] ALFREDAPI-524: Tiny clean up settings.gradle --- settings.gradle | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/settings.gradle b/settings.gradle index ead63ac1..991b52c3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,16 +8,14 @@ include ':apix-docker' include ':apix-integrationtests' include ':apix-integrationtests:model-amp' -ext { - versions = ["6.2", "7.0", "7.1", "7.2", "7.3"] -} +for (String version : ["6.2", "7.0", "7.1", "7.2", "7.3"]) { + def shortVersion = version.replaceAll("\\.", "") -for(String version : versions) { - def shortVersion = version.replaceAll("\\.","") include ":apix-impl:apix-impl-$shortVersion" include ":alfresco:$shortVersion" include ":apix-docker:docker-$shortVersion" include ":apix-integrationtests:alfresco:$shortVersion" + project(":apix-impl:apix-impl-$shortVersion").projectDir = "$rootDir/apix-impl/$shortVersion" as File project(":apix-docker:docker-$shortVersion").projectDir = "$rootDir/apix-docker/$shortVersion" as File project(":alfresco:$shortVersion").projectDir = "$rootDir/alfresco/$shortVersion" as File From 5541c1aa8f20d8b902181abdc2c732d42430a7a5 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 28 Jun 2023 12:01:42 +0200 Subject: [PATCH 53/90] ALFREDAPI-524: Revert to -SNAPSHOT Which is now possible because we don't use OSGi anymore. --- build.gradle | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 641dff7f..b70d4cb9 100644 --- a/build.gradle +++ b/build.gradle @@ -12,9 +12,7 @@ plugins { def static getVersionQualifier(String branch_name) { if(branch_name.startsWith('release')) return '' - // Osgi in 5x accepts - in qualifier, 6x does not. - // Suggest removing branch section from snapshot qualifiers all together. - return '.SNAPSHOT' + return '-SNAPSHOT' } ext { From fa36d77313a12169fc9b58b4d4e30f4662b0bbeb Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 28 Jun 2023 12:01:42 +0200 Subject: [PATCH 54/90] ALFREDAPI-524: Fix Alf Nexus credentials in CI --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3784eb2..07266124 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,6 +2,9 @@ name: 'Continuous Integration' on: push: workflow_dispatch: +env: + ALFRESCO_NEXUS_USERNAME: ${{ secrets.ALFRESCO_NEXUS_USERNAME }} + ALFRESCO_NEXUS_PASSWORD: ${{ secrets.ALFRESCO_NEXUS_PASSWORD }} jobs: BuildAndPublish: strategy: From 0b6b2125736b380341c86884b218ab09d4bc9b0f Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 28 Jun 2023 12:01:42 +0200 Subject: [PATCH 55/90] ALFREDAPI-524: (Security) gradle build action to 2.4.2 --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07266124..d722ae11 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,11 +32,11 @@ jobs: arguments: :apix-interface:build :apix-interface:javadoc - name: Unit test REST API - uses: gradle/gradle-build-action@v2.3.0 + uses: gradle/gradle-build-action@v2.4.2 with: arguments: --info :apix-rest-v1:test - name: Build and test - uses: gradle/gradle-build-action@v2.3.0 + uses: gradle/gradle-build-action@v2.4.2 with: arguments: >- --info @@ -53,7 +53,7 @@ jobs: - name: Publish if: ${{ startsWith(github.ref, 'refs/heads/master') || startsWith(github.ref, 'refs/heads/release') }}" - uses: gradle/gradle-build-action@v2.3.0 + uses: gradle/gradle-build-action@v2.4.2 env: ORG_GRADLE_PROJECT_signingKey: ${{ secrets.MAVEN_CENTRAL_GPG_KEY }} ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.MAVEN_CENTRAL_GPG_PASSWORD }} From 96b8c1dd3363da243b698c9fed017a6b477b4f5b Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 28 Jun 2023 12:01:42 +0200 Subject: [PATCH 56/90] ALFREDAPI-524: Update gradle 'decription' to 'Alfred API' --- alfresco/73/overrides.gradle | 2 +- apix-impl/build.gradle | 2 +- .../java/eu/xenit/apix/alfresco/version/VersionService.java | 2 +- apix-interface/build.gradle | 2 +- apix-rest-v1/build.gradle | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/alfresco/73/overrides.gradle b/alfresco/73/overrides.gradle index cd463bee..daf6b9d3 100644 --- a/alfresco/73/overrides.gradle +++ b/alfresco/73/overrides.gradle @@ -1,4 +1,4 @@ -description = "Xenit API-X implementation Alfresco 7.3" +description = "Xenit Alfred API implementation Alfresco 7.3" ext { alfresco_version = '7.3.1' diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index 47e42e50..f46d9573 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -61,7 +61,7 @@ allprojects { /* * WARNING: THIS FILE IS AUTO-GENERATED BY GRADLE DURING BUILD. * ANY CHANGES TO THIS FILE WILL BE LOST AFTER NEW BUILD. - * SEE task generateVersionFile IN api-x_dynamicextensions/build.gradle + * SEE Gradle task generateVersionFile */ public class Version { public static final String Number = "${project.versionWithoutQualifier}"; diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/version/VersionService.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/version/VersionService.java index 0eec1e24..02b02a68 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/version/VersionService.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/version/VersionService.java @@ -12,7 +12,7 @@ public class VersionService implements IVersionService { public VersionDescription getVersionDescription() { VersionDescription ret = VersionDescription.createFromVersionString( Version.Number, - "XeniT Api-X java alfresco wrapper and REST interface"); + "Xenit Alfred API Alfresco wrapper and REST interface"); return ret; } } diff --git a/apix-interface/build.gradle b/apix-interface/build.gradle index ae05a9a2..d9bae88b 100644 --- a/apix-interface/build.gradle +++ b/apix-interface/build.gradle @@ -1,4 +1,4 @@ -description = 'Xenit API-X Java interface' +description = 'Xenit Alfred API Java interface' apply from: "${rootProject.projectDir}/publish.gradle" diff --git a/apix-rest-v1/build.gradle b/apix-rest-v1/build.gradle index 8f2ff63e..295dcbaa 100644 --- a/apix-rest-v1/build.gradle +++ b/apix-rest-v1/build.gradle @@ -4,7 +4,7 @@ plugins { id 'eu.xenit.alfresco' version '1.1.0' } -description = 'Xenit API-X Rest v1' +description = 'Xenit Alfred API Rest v1' apply from: "$rootProject.projectDir/alfresco/70/overrides.gradle" From 62f86f838d9532c00170888c4a9f3124481deb40 Mon Sep 17 00:00:00 2001 From: Hechmi Dammak Date: Thu, 31 Aug 2023 11:36:34 +0100 Subject: [PATCH 57/90] ALFREDAPI-531 fix facet qname splitting --- CHANGELOG.md | 1 + .../search/SearchFacetsServiceImpl.java | 6 +-- .../search/SearchFacetServiceUnitTest.java | 54 +++++++++++++++---- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49e0676f..3107bf2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ to `eu.xenit.alfred.api`. ### Changed ### Fixed +* [ALFREDAPI-531](https://xenitsupport.jira.com/browse/ALFREDAPI-531): Fix facet qname splitting for dates * [ALFREDAPI-520](https://xenitsupport.jira.com/browse/ALFREDAPI-520): Enforce encoding on bulk json responses to guarantee clean text ### Removed diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/search/SearchFacetsServiceImpl.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/search/SearchFacetsServiceImpl.java index 6201ee3a..cc505c9e 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/search/SearchFacetsServiceImpl.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/search/SearchFacetsServiceImpl.java @@ -248,8 +248,8 @@ private Map> getFacetResults(SearchParameters sp // facetTokenName => @{http://www.alfresco.org/model/content/1.0}created // qName => {http://www.alfresco.org/model/content/1.0}created // 7 => {!afts} - key = key.substring(7); - String facetTokenName = key.substring(0, key.lastIndexOf(':')); + key = key.replace("{!afts}",""); + String facetTokenName = key.substring(0, key.indexOf(":[")); String qName = facetTokenToQname(facetTokenName); // Retrieve the previous facet queries @@ -260,7 +260,7 @@ private Map> getFacetResults(SearchParameters sp // Get the handler for this qName FacetLabelDisplayHandler handler = facetLabelDisplayHandlerRegistry.getDisplayHandler(facetTokenName); - String val = key.substring(key.indexOf('}') + key.substring(key.indexOf('}')).indexOf(':') + 1); + String val = key.substring( key.indexOf(":[") + 1); FacetLabel facetLabel = (handler == null) ? new FacetLabel(val, val, -1) : handler.getDisplayLabel(key); // See if we have a nice textual version of this label diff --git a/apix-impl/src/test/java/eu/xenit/apix/tests/search/SearchFacetServiceUnitTest.java b/apix-impl/src/test/java/eu/xenit/apix/tests/search/SearchFacetServiceUnitTest.java index 1a5f9670..f871bb21 100644 --- a/apix-impl/src/test/java/eu/xenit/apix/tests/search/SearchFacetServiceUnitTest.java +++ b/apix-impl/src/test/java/eu/xenit/apix/tests/search/SearchFacetServiceUnitTest.java @@ -1,21 +1,11 @@ package eu.xenit.apix.tests.search; -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - import eu.xenit.apix.alfresco.search.SearchFacetsService; import eu.xenit.apix.alfresco.search.SearchFacetsServiceImpl; import eu.xenit.apix.search.FacetSearchResult; import eu.xenit.apix.search.FacetSearchResult.FacetValue; import eu.xenit.apix.search.SearchQuery.FacetOptions; import eu.xenit.apix.translation.ITranslationService; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint; import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper; import org.alfresco.repo.search.impl.solr.facet.SolrFacetService; @@ -34,6 +24,17 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + public class SearchFacetServiceUnitTest { @Autowired @@ -110,7 +111,11 @@ public void initMocks() { .thenReturn(languageFieldFacetResults); when(resultSetMock.getFieldFacet("@{http://test.apix.xenit.eu/model/content}documentStatus")) .thenReturn(documentStatusFieldFacetResults); - when(resultSetMock.getFacetQueries()).thenReturn(new HashMap()); + Map facetQueries = new HashMap<>(); + facetQueries.put("{!afts}@{http://www.alfresco.org/model/content/1.0}content.size:[0 TO 10240]", 1); + facetQueries.put("{!afts}@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-1YEAR TO NOW/DAY+1DAY]", 2); + facetQueries.put("{!afts}@{http://www.alfresco.org/model/content/1.0}created:[2020-08-31T07:00:00.000Z TO 2023-09-02T10:01:00.000Z]", 1); + when(resultSetMock.getFacetQueries()).thenReturn(facetQueries); searchParametersMock = mock(SearchParameters.class); List fieldFacets = new ArrayList<>(); @@ -145,6 +150,33 @@ public List initExpectedResult_for_assertThat_getFacetResults documentStatusValues.add(draftFacetValue); documentStatusResult.setValues(documentStatusValues); expectedResult.add(documentStatusResult); + FacetSearchResult contentResult = new FacetSearchResult(); + contentResult.setName("{http://www.alfresco.org/model/content/1.0}content.size"); + List contentValues = new ArrayList<>(); + FacetValue contentFacetValue = new FacetValue(); + contentFacetValue.setValue("[0 TO 10240]"); + contentFacetValue.setCount(1); + contentValues.add(contentFacetValue); + contentResult.setValues(contentValues); + expectedResult.add(contentResult); + FacetSearchResult modifiedResult = new FacetSearchResult(); + modifiedResult.setName("{http://www.alfresco.org/model/content/1.0}modified"); + List modifiedValues = new ArrayList<>(); + FacetValue modifiedFacetValue = new FacetValue(); + modifiedFacetValue.setValue("[NOW/DAY-1YEAR TO NOW/DAY+1DAY]"); + modifiedFacetValue.setCount(2); + modifiedValues.add(modifiedFacetValue); + modifiedResult.setValues(modifiedValues); + expectedResult.add(modifiedResult); + FacetSearchResult createdResult = new FacetSearchResult(); + createdResult.setName("{http://www.alfresco.org/model/content/1.0}created"); + List createdValues = new ArrayList<>(); + FacetValue createdFacetValue = new FacetValue(); + createdFacetValue.setValue("[2020-08-31T07:00:00.000Z TO 2023-09-02T10:01:00.000Z]"); + createdFacetValue.setCount(1); + createdValues.add(createdFacetValue); + createdResult.setValues(createdValues); + expectedResult.add(createdResult); return expectedResult; } From 8a88a3d5015ac124523801626622fe2c3898511f Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 22 Nov 2023 13:33:14 +0100 Subject: [PATCH 58/90] ALFREDAPI-519: Update Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3107bf2a..4b5299ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ To make this change clearer the Alfred API Maven group ID has been updated from to `eu.xenit.alfred.api`. ### Added +* [ALFREDAPI-519](https://xenitsupport.jira.com/browse/ALFREDAPI-519): Add support for Alfresco 7.4 ### Changed From d41e380a3adb06ca88402ea6b2b3bc5f5177a560 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 22 Nov 2023 13:33:14 +0100 Subject: [PATCH 59/90] ALFREDAPI-519: Add file structure for 74 --- alfresco/73/overrides.gradle | 4 +- alfresco/74/overrides.gradle | 8 ++++ apix-docker/74/build.gradle | 8 ++++ .../74/debug-extension.docker-compose.yml | 16 +++++++ apix-docker/74/docker-compose.yml | 48 +++++++++++++++++++ apix-impl/74/.gitkeep | 0 apix-impl/build.gradle | 2 +- apix-integrationtests/alfresco/74/.gitkeep | 0 apix-integrationtests/alfresco/build.gradle | 2 +- settings.gradle | 4 +- 10 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 alfresco/74/overrides.gradle create mode 100644 apix-docker/74/build.gradle create mode 100644 apix-docker/74/debug-extension.docker-compose.yml create mode 100644 apix-docker/74/docker-compose.yml create mode 100644 apix-impl/74/.gitkeep create mode 100644 apix-integrationtests/alfresco/74/.gitkeep diff --git a/alfresco/73/overrides.gradle b/alfresco/73/overrides.gradle index daf6b9d3..e48c594e 100644 --- a/alfresco/73/overrides.gradle +++ b/alfresco/73/overrides.gradle @@ -2,8 +2,6 @@ description = "Xenit Alfred API implementation Alfresco 7.3" ext { alfresco_version = '7.3.1' - alfresco_repo_version = '17.175' alfresco_min_version = alfresco_version.substring(0, 3) + ".0" - //Not setting alfresco_max_version here to make it easier to test on next Alfresco version (only for latest version) - alfresco_max_version = null // explicit null to overwrite properties from other projects (e.g. 7.2) + alfresco_max_version = alfresco_version.substring(0, 3) + ".99" } \ No newline at end of file diff --git a/alfresco/74/overrides.gradle b/alfresco/74/overrides.gradle new file mode 100644 index 00000000..725d90ca --- /dev/null +++ b/alfresco/74/overrides.gradle @@ -0,0 +1,8 @@ +description = "Xenit Alfred API implementation Alfresco 7.4" + +ext { + alfresco_version = '7.4.0' + alfresco_min_version = alfresco_version.substring(0, 3) + ".0" + //Not setting alfresco_max_version here to make it easier to test on next Alfresco version (only for latest version) + alfresco_max_version = null // explicit null to overwrite properties from other projects +} \ No newline at end of file diff --git a/apix-docker/74/build.gradle b/apix-docker/74/build.gradle new file mode 100644 index 00000000..34762dcb --- /dev/null +++ b/apix-docker/74/build.gradle @@ -0,0 +1,8 @@ +dependencies { + baseAlfrescoWar platform("org.alfresco:acs-packaging:7.4.0.1") + baseAlfrescoWar 'org.alfresco:content-services@war' +} + +dockerAlfresco { + baseImage = 'private.docker.xenit.eu/alfresco-enterprise/alfresco-repository-enterprise:7.4.0.1' +} diff --git a/apix-docker/74/debug-extension.docker-compose.yml b/apix-docker/74/debug-extension.docker-compose.yml new file mode 100644 index 00000000..825ba2ab --- /dev/null +++ b/apix-docker/74/debug-extension.docker-compose.yml @@ -0,0 +1,16 @@ +version: '2' +services: + alfresco-core: + ports: + - 8000:8000 + environment: + - DEBUG=true + - SHARE_HOST=alfresco-share + alfresco-share: + image: docker.io/xenit/alfresco-share-community:7.4 + ports: + - 8090:8080 + environment: + - DEBUG=true + - ALFRESCO_HOST=alfresco-core + - ALFRESCO_INTERNAL_HOST=alfresco-core \ No newline at end of file diff --git a/apix-docker/74/docker-compose.yml b/apix-docker/74/docker-compose.yml new file mode 100644 index 00000000..6c13c868 --- /dev/null +++ b/apix-docker/74/docker-compose.yml @@ -0,0 +1,48 @@ +version: '2' + +services: + alfresco-core: + image: ${DOCKER_IMAGE} + ports: + - "${DOCKER_IP}::8080" + volumes: + - alfresco:/opt/alfresco/alf_data + restart: unless-stopped + environment: + - SOLR_HOST=solr + - TERM=xterm + - GLOBAL_messaging.broker.url=failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true + - GLOBAL_localTransform.core-aio.url=http://transform-core-aio:8090/ + + solr: + image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.8.2 + volumes: + - solr:/opt/alfresco/alf_data + restart: unless-stopped + environment: + - ALFRESCO_HOST=alfresco-core + + postgresql: + image: docker.io/xenit/postgres + volumes: + - postgres:/var/lib/postgresql/data + environment: + - POSTGRES_USER=alfresco + - POSTGRES_PASSWORD=admin + - POSTGRES_DB=alfresco + restart: unless-stopped + + activemq: + image: alfresco/alfresco-activemq:5.16.1 + mem_limit: 1g + + transform-core-aio: + image: alfresco/alfresco-transform-core-aio:2.5.0 + environment: + JAVA_OPTS: " -Xms256m -Xmx512m" + ACTIVEMQ_URL: "nio://activemq:61616" + +volumes: + alfresco: + solr: + postgres: diff --git a/apix-impl/74/.gitkeep b/apix-impl/74/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index f46d9573..65e2e67d 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -24,7 +24,7 @@ subprojects { } allprojects { - // Subproject of supported Alfresco version 62/70/71/72/73 + // Subproject of supported Alfresco versions def subproject_alfresco_version = project.projectDir.name == "apix-impl" ? "70" : project.projectDir.name apply from: "$rootProject.projectDir/alfresco/${subproject_alfresco_version}/overrides.gradle" diff --git a/apix-integrationtests/alfresco/74/.gitkeep b/apix-integrationtests/alfresco/74/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apix-integrationtests/alfresco/build.gradle b/apix-integrationtests/alfresco/build.gradle index 0e6987c3..8e54c5f1 100644 --- a/apix-integrationtests/alfresco/build.gradle +++ b/apix-integrationtests/alfresco/build.gradle @@ -73,7 +73,7 @@ allprojects { } subprojects { - // Subproject of supported Alfresco version 61/62/70/71/72 + // Subproject of supported Alfresco versions def projectApixImpl = project(":apix-impl:apix-impl-${project.projectDir.name}") def projectDocker = project(":apix-docker:docker-${project.projectDir.name}") evaluationDependsOn(projectApixImpl.path) diff --git a/settings.gradle b/settings.gradle index 991b52c3..5acc856b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,8 +8,8 @@ include ':apix-docker' include ':apix-integrationtests' include ':apix-integrationtests:model-amp' -for (String version : ["6.2", "7.0", "7.1", "7.2", "7.3"]) { - def shortVersion = version.replaceAll("\\.", "") +for (String version : ['6.2', '7.0', '7.1', '7.2', '7.3', '7.4']) { + def shortVersion = version.replaceAll('\\.', '') include ":apix-impl:apix-impl-$shortVersion" include ":alfresco:$shortVersion" From 3737071cfdbb2b8da07e663c74d39db5d9f24f46 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 22 Nov 2023 13:33:14 +0100 Subject: [PATCH 60/90] ALFREDAPI-519: Bump snakeyaml to 2.0 --- apix-impl/build.gradle | 2 +- .../apix/alfresco/configuration/ConfigurationServiceImpl.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index 65e2e67d..22f53f23 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -43,7 +43,7 @@ allprojects { alfrescoProvided("org.alfresco:alfresco-repository") alfrescoProvided('org.alfresco:alfresco-remote-api') - implementation group: 'org.yaml', name: 'snakeyaml', version: '1.15' + implementation group: 'org.yaml', name: 'snakeyaml', version: '2.0' implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final' testImplementation platform("org.alfresco:acs-community-packaging:${alfresco_version}") diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java index 8beefa51..665bdcff 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java @@ -20,6 +20,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; @@ -84,7 +85,7 @@ public Configurations getConfigurationFiles(String searchDirectory, String nameF logger.debug("Found {} configuration files: {}", configurationFiles.size(), configurationFiles); - Yaml yamlMapper = new Yaml(new SafeConstructor()); + Yaml yamlMapper = new Yaml(new SafeConstructor(new LoaderOptions())); ObjectMapper jsonMapper = new ObjectMapper(new JsonFactory()); for (ConfigurationFile configurationFile : configurationFiles) { From 3fe484891975b70df7a39bbd3607b71b6cd5b18a Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 22 Nov 2023 13:33:14 +0100 Subject: [PATCH 61/90] ALFREDAPI-519: Bump DE to 3.1.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b70d4cb9..756edba8 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ def static getVersionQualifier(String branch_name) { ext { versionWithoutQualifier = '4.1.0' - de_version = '3.0.0' + de_version = '3.1.0' mvc = '8.0.0' jackson_version = '2.8.3' care4alfVersion = '2.3.0' From d732b1127d8ba439484926137d8d1511fa4c98ac Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 22 Nov 2023 13:33:14 +0100 Subject: [PATCH 62/90] ALFREDAPI-519: Remove spring source repo --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index 756edba8..4f457e4a 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,6 @@ subprojects { repositories { mavenCentral() maven { url "https://artifacts.alfresco.com/nexus/content/groups/public" } - maven { url "https://repo.springsource.org/release" } // This private repository provides Xenit with Alfresco enterprise artefacts. // External developers should replace it with their own library repository. maven { From 01b21e7d966697a67bdcbb07667ef1b3333a17f8 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 22 Nov 2023 13:33:14 +0100 Subject: [PATCH 63/90] ALFREDAPI-519: Add 74 to build --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d722ae11..61b5be9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: BuildAndPublish: strategy: matrix: - alfresco_version: [ 62, 70, 71, 72, 73 ] + alfresco_version: [ 62, 70, 71, 72, 73, 74 ] runs-on: ubuntu-latest steps: - name: Check out From f3c3f46e0ce1cbb295ccce66706b1f1d80c95579 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 22 Nov 2023 13:33:14 +0100 Subject: [PATCH 64/90] ALFREDAPI-519: Quick fix BND with multi-releases --- apix-integrationtests/alfresco/build.gradle | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apix-integrationtests/alfresco/build.gradle b/apix-integrationtests/alfresco/build.gradle index 8e54c5f1..7b238754 100644 --- a/apix-integrationtests/alfresco/build.gradle +++ b/apix-integrationtests/alfresco/build.gradle @@ -1,6 +1,6 @@ def integrationTestsProjectDir = project.projectDir allprojects { - // Subproject of supported Alfresco version 61/62/70/71/72 + // Subproject of supported Alfresco versions def subproject_alfresco_version = project.projectDir.name == "alfresco" ? "70" // minimum supported version : project.projectDir.name @@ -121,5 +121,10 @@ subprojects { // After the tests, the docker setup should be stopped finalizedBy composeDownTask } + + // Fix to let BND deal with multi-releases of snakeyaml + integrationTestFatJar { + bnd('-fixupmessages': '^Classes found in the wrong directory: \\\\{META-INF/versions/9/.*') + } } From a226def4f0906a27b743f5a409e29bc0e4731f0d Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 22 Nov 2023 13:33:14 +0100 Subject: [PATCH 65/90] ALFREDAPI-519: Explain how to run a single test --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 1690e521..962fbc9b 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,10 @@ However, this starts (and afterwards stops) docker containers. This includes sta ./gradlew -x composeUp -x composeDown :apix-integrationtests:test-61:integrationTest -Pprotocol=http -Phost=localhost -Pport=8061 ``` +If you only want to run specific tests, you can specify this on the Gradle invocation with a pattern. For example: + ```bash +./gradlew :apix-integrationtests:alfresco:74:integrationTest -x composeDown --tests C*ServiceTest + ``` #### Run integration tests under debugger 1. Debugging settings are already added by `apix-docker/${VERSION}/debug-extension.docker-compose.yml`, including a From 5ec4a011b8f2d0b74019f85cee948f9b1d026598 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 22 Nov 2023 13:33:14 +0100 Subject: [PATCH 66/90] ALFREDAPI-519: Replace snakeyaml by jackson-databind-yaml --- apix-impl/build.gradle | 11 ++++---- .../ConfigurationServiceImpl.java | 28 +++++++++---------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/apix-impl/build.gradle b/apix-impl/build.gradle index 22f53f23..565b7abe 100644 --- a/apix-impl/build.gradle +++ b/apix-impl/build.gradle @@ -37,14 +37,13 @@ allprojects { exclude group: 'com.fasterxml.jackson.core', module: 'jackson-annotations' exclude group: 'com.fasterxml.jackson.core', module: 'jackson-databind' } - implementation 'commons-lang:commons-lang:1.0' + implementation group: 'commons-lang', name: 'commons-lang', version: '1.0' + implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final' + implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.16.0' alfrescoProvided platform("org.alfresco:acs-community-packaging:${alfresco_version}") - alfrescoProvided("org.alfresco:alfresco-repository") - alfrescoProvided('org.alfresco:alfresco-remote-api') - - implementation group: 'org.yaml', name: 'snakeyaml', version: '2.0' - implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final' + alfrescoProvided "org.alfresco:alfresco-repository" + alfrescoProvided 'org.alfresco:alfresco-remote-api' testImplementation platform("org.alfresco:acs-community-packaging:${alfresco_version}") testImplementation 'org.alfresco:alfresco-repository' diff --git a/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java b/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java index 665bdcff..1f668d05 100644 --- a/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java +++ b/apix-impl/src/main/java/eu/xenit/apix/alfresco/configuration/ConfigurationServiceImpl.java @@ -1,7 +1,11 @@ package eu.xenit.apix.alfresco.configuration; +import static org.alfresco.model.ContentModel.PROP_NAME; +import static org.alfresco.model.ContentModel.TYPE_FOLDER; + import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import eu.xenit.apix.configuration.ConfigurationFile; import eu.xenit.apix.configuration.ConfigurationFileFlags; import eu.xenit.apix.configuration.ConfigurationService; @@ -14,25 +18,18 @@ import eu.xenit.apix.node.ChildParentAssociation; import eu.xenit.apix.node.INodeService; import eu.xenit.apix.node.NodeMetadata; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.yaml.snakeyaml.LoaderOptions; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.SafeConstructor; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; - -import static org.alfresco.model.ContentModel.PROP_NAME; -import static org.alfresco.model.ContentModel.TYPE_FOLDER; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; @Service("eu.xenit.apix.configuration.ConfigurationService") public class ConfigurationServiceImpl implements ConfigurationService { @@ -85,7 +82,6 @@ public Configurations getConfigurationFiles(String searchDirectory, String nameF logger.debug("Found {} configuration files: {}", configurationFiles.size(), configurationFiles); - Yaml yamlMapper = new Yaml(new SafeConstructor(new LoaderOptions())); ObjectMapper jsonMapper = new ObjectMapper(new JsonFactory()); for (ConfigurationFile configurationFile : configurationFiles) { @@ -116,7 +112,9 @@ public Configurations getConfigurationFiles(String searchDirectory, String nameF logger.debug("Mimetype is {}; filename is {}", mimetype, name); Object parsedContent = null; if (mimetype.equals("text/x-yaml") || name.endsWith(".yaml") || name.endsWith(".yml")) { - parsedContent = yamlMapper.loadAs(configStream.getInputStream(), Object.class); + ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); + yamlMapper.findAndRegisterModules(); + parsedContent = yamlMapper.readValue(configStream.getInputStream(), Object.class); } else if (mimetype.equals("application/json") || name.endsWith(".json")) { parsedContent = jsonMapper.readValue(configStream.getInputStream(), Object.class); } else { From 56958459865a1ae205d0d1fd2f43862580b4c743 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 29 Nov 2023 14:47:22 +0100 Subject: [PATCH 67/90] ALFREDAPI-519: Bump DE to 3.1.0 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 4f457e4a..fb837a96 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { // Centralize plugin version management id 'be.vbgn.ci-detect' version '0.5.0' apply false - id 'eu.xenit.de' version '3.0.0' apply false + id 'eu.xenit.de' version '3.1.0' apply false id 'eu.xenit.amp' version '1.1.0' apply false id 'eu.xenit.alfresco' version '1.1.0' apply false id 'eu.xenit.docker-alfresco' version '5.3.1' apply false @@ -18,7 +18,7 @@ def static getVersionQualifier(String branch_name) { ext { versionWithoutQualifier = '4.1.0' - de_version = '3.1.0' + de_version = '3.1.0' // Only used for integration testing mvc = '8.0.0' jackson_version = '2.8.3' care4alfVersion = '2.3.0' From 1e88b2f9823228563262a759a4622671e9db2718 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 29 Nov 2023 14:47:22 +0100 Subject: [PATCH 68/90] ALFREDAPI-519: Improve BND fix regex --- apix-integrationtests/alfresco/build.gradle | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apix-integrationtests/alfresco/build.gradle b/apix-integrationtests/alfresco/build.gradle index 7b238754..6d6f183b 100644 --- a/apix-integrationtests/alfresco/build.gradle +++ b/apix-integrationtests/alfresco/build.gradle @@ -122,9 +122,10 @@ subprojects { finalizedBy composeDownTask } - // Fix to let BND deal with multi-releases of snakeyaml + // Fix to let BND deal with multi-releases JARs + // So far this only applies to snakeyaml integrationTestFatJar { - bnd('-fixupmessages': '^Classes found in the wrong directory: \\\\{META-INF/versions/9/.*') + bnd('-fixupmessages': '^Classes found in the wrong directory: \\\\{META-INF/versions/.*') } } From b4af1fab1e2e4d50653f5f6eee09930bd1c57101 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 29 Nov 2023 14:47:22 +0100 Subject: [PATCH 69/90] ALFREDAPI-519: Make test jobs continue on failure of others --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 61b5be9c..e5e0845d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,7 @@ jobs: strategy: matrix: alfresco_version: [ 62, 70, 71, 72, 73, 74 ] + fail-fast: false runs-on: ubuntu-latest steps: - name: Check out From ecb204f9b8d1f478778546fa64028282ea6b9adf Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 29 Nov 2023 14:47:22 +0100 Subject: [PATCH 70/90] ALFREDAPI-519: Drop support for Alfresco 6.2 --- .github/workflows/ci.yml | 2 +- CHANGELOG.md | 5 ++- alfresco/62/overrides.gradle | 5 --- apix-docker/62/build.gradle | 10 ----- .../62/debug-extension.docker-compose.yml | 16 -------- apix-docker/62/docker-compose.yml | 37 ------------------- apix-impl/62/.gitkeep | 0 apix-integrationtests/alfresco/61/.gitkeep | 0 apix-integrationtests/alfresco/62/.gitkeep | 0 build.gradle | 2 +- settings.gradle | 2 +- 11 files changed, 7 insertions(+), 72 deletions(-) delete mode 100644 alfresco/62/overrides.gradle delete mode 100644 apix-docker/62/build.gradle delete mode 100644 apix-docker/62/debug-extension.docker-compose.yml delete mode 100644 apix-docker/62/docker-compose.yml delete mode 100644 apix-impl/62/.gitkeep delete mode 100644 apix-integrationtests/alfresco/61/.gitkeep delete mode 100644 apix-integrationtests/alfresco/62/.gitkeep diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5e0845d..2bb5e748 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: BuildAndPublish: strategy: matrix: - alfresco_version: [ 62, 70, 71, 72, 73, 74 ] + alfresco_version: [ 70, 71, 72, 73, 74 ] fail-fast: false runs-on: ubuntu-latest steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b5299ec..ee872aca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,14 @@ # Alfred API - Changelog -## 4.1.0 (unreleased) +## 5.0.0 (unreleased) From this version onward Dynamic Extensions is replaced by [Alfresco MVC](https://github.com/dgradecak/alfresco-mvc) as framework to reduce maintenance efforts. To make this change clearer the Alfred API Maven group ID has been updated from `eu.xenit.apix` to `eu.xenit.alfred.api`. +This release also drop* support for Alfresco 6.2 and adds support for 7.4. + ### Added * [ALFREDAPI-519](https://xenitsupport.jira.com/browse/ALFREDAPI-519): Add support for Alfresco 7.4 @@ -18,6 +20,7 @@ to `eu.xenit.alfred.api`. ### Removed * [ALFREDAPI-504](https://xenitsupport.jira.com/browse/ALFREDAPI-504): Drop Dynamic Extensions in favor of Alfresco MVC +* [ALFREDAPI-519](https://xenitsupport.jira.com/browse/ALFREDAPI-519): Remove support for Alfresco 6.2 diff --git a/alfresco/62/overrides.gradle b/alfresco/62/overrides.gradle deleted file mode 100644 index 0cf8430f..00000000 --- a/alfresco/62/overrides.gradle +++ /dev/null @@ -1,5 +0,0 @@ -ext { - alfresco_version = "6.2.0-ga" - alfresco_min_version = alfresco_version.substring(0, 3) + ".0" - alfresco_max_version = alfresco_version.substring(0, 3) + ".99" -} \ No newline at end of file diff --git a/apix-docker/62/build.gradle b/apix-docker/62/build.gradle deleted file mode 100644 index 8324cebd..00000000 --- a/apix-docker/62/build.gradle +++ /dev/null @@ -1,10 +0,0 @@ -dependencies { - baseAlfrescoWar platform("org.alfresco:acs-packaging:6.2.2.19") - baseAlfrescoWar 'org.alfresco:content-services@war' - // Fix for https://github.com/xenit-eu/dynamic-extensions-for-alfresco#alfresco-61---wrong-version-of-commons-annotations-used - alfrescoAmp(group: 'eu.xenit.alfresco', name: 'alfresco-hotfix-MNT-20557', version: '1.0.2', ext: 'amp') -} - -dockerAlfresco { - baseImage = 'private.docker.xenit.eu/alfresco-enterprise/alfresco-repository-enterprise:6.2.2.19' -} \ No newline at end of file diff --git a/apix-docker/62/debug-extension.docker-compose.yml b/apix-docker/62/debug-extension.docker-compose.yml deleted file mode 100644 index d9b4673a..00000000 --- a/apix-docker/62/debug-extension.docker-compose.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: '2' -services: - alfresco-core: - ports: - - 8000:8000 - environment: - - DEBUG=true - - SHARE_HOST=alfresco-share - alfresco-share: - image: hub.xenit.eu/public/alfresco-share-community:6.1 - ports: - - 8090:8080 - environment: - - DEBUG=true - - ALFRESCO_HOST=alfresco-core - - ALFRESCO_INTERNAL_HOST=alfresco-core diff --git a/apix-docker/62/docker-compose.yml b/apix-docker/62/docker-compose.yml deleted file mode 100644 index 2e484c28..00000000 --- a/apix-docker/62/docker-compose.yml +++ /dev/null @@ -1,37 +0,0 @@ -version: '2' - -services: - alfresco-core: - image: ${DOCKER_IMAGE} - ports: - - ${DOCKER_IP}::8080 - volumes: - - alfresco:/opt/alfresco/alf_data - restart: unless-stopped - environment: - - TERM=xterm - - solr: - image: private.docker.xenit.eu/alfresco-enterprise/alfresco-solr6:2.0.3 - restart: unless-stopped - environment: - - ALFRESCO_HOST=alfresco-core - - postgresql: - image: docker.io/xenit/postgres - volumes: - - postgres:/var/lib/postgresql/data - environment: - - POSTGRES_USER=alfresco - - POSTGRES_PASSWORD=admin - - POSTGRES_DB=alfresco - restart: unless-stopped - - jodconverter: - image: hub.xenit.eu/public/jodconverter-ws - restart: unless-stopped - -volumes: - alfresco: - solr: - postgres: \ No newline at end of file diff --git a/apix-impl/62/.gitkeep b/apix-impl/62/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/apix-integrationtests/alfresco/61/.gitkeep b/apix-integrationtests/alfresco/61/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/apix-integrationtests/alfresco/62/.gitkeep b/apix-integrationtests/alfresco/62/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/build.gradle b/build.gradle index fb837a96..ef191e23 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ def static getVersionQualifier(String branch_name) { } ext { - versionWithoutQualifier = '4.1.0' + versionWithoutQualifier = '5.0.0' de_version = '3.1.0' // Only used for integration testing mvc = '8.0.0' diff --git a/settings.gradle b/settings.gradle index 5acc856b..4a170df9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,7 +8,7 @@ include ':apix-docker' include ':apix-integrationtests' include ':apix-integrationtests:model-amp' -for (String version : ['6.2', '7.0', '7.1', '7.2', '7.3', '7.4']) { +for (String version : ['7.0', '7.1', '7.2', '7.3', '7.4']) { def shortVersion = version.replaceAll('\\.', '') include ":apix-impl:apix-impl-$shortVersion" From f94dc05dbf3baf3a8bda04a0109a6b2c782c3bb2 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Wed, 29 Nov 2023 14:47:22 +0100 Subject: [PATCH 71/90] ALFREDAPI-519: Bump gradle wrapper to 8.5 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e0b9fcdc..ef3f3c22 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ #Mon Nov 04 15:47:31 CET 2019 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStorePath=wrapper/dists From b1e534ee2d6efdeab3e4ebe8edc072ce8a130275 Mon Sep 17 00:00:00 2001 From: Wim Date: Mon, 4 Dec 2023 08:51:38 +0100 Subject: [PATCH 72/90] ALFREDAPI-532: Fix :apix-interface:javadoc --- CHANGELOG.md | 3 ++- apix-interface/build.gradle | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee872aca..89be94e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,8 +15,9 @@ This release also drop* support for Alfresco 6.2 and adds support for 7.4. ### Changed ### Fixed -* [ALFREDAPI-531](https://xenitsupport.jira.com/browse/ALFREDAPI-531): Fix facet qname splitting for dates * [ALFREDAPI-520](https://xenitsupport.jira.com/browse/ALFREDAPI-520): Enforce encoding on bulk json responses to guarantee clean text +* [ALFREDAPI-531](https://xenitsupport.jira.com/browse/ALFREDAPI-531): Fix facet qname splitting for dates +* [ALFREDAPI-532](https://xenitsupport.jira.com/browse/ALFREDAPI-532): Fix :apix-interface:javadoc ### Removed * [ALFREDAPI-504](https://xenitsupport.jira.com/browse/ALFREDAPI-504): Drop Dynamic Extensions in favor of Alfresco MVC diff --git a/apix-interface/build.gradle b/apix-interface/build.gradle index d9bae88b..5aeaf098 100644 --- a/apix-interface/build.gradle +++ b/apix-interface/build.gradle @@ -10,8 +10,6 @@ task sourcesJar(type: Jar) { task javadocJar(type: Jar) { from javadoc archiveClassifier = 'javadoc' - // Temporary workaround for https://bugs.openjdk.java.net/browse/JDK-8244171 - javadoc.options.addBooleanOption("-no-module-directories", true) } publishing { From 2e6993e960c44716553f7ed21caab8f241d21494 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Thu, 30 Nov 2023 16:12:36 +0100 Subject: [PATCH 73/90] ALFREDAPI-527: Put in fixed ports --- apix-docker/70/docker-compose.yml | 2 +- apix-docker/71/docker-compose.yml | 2 +- apix-docker/72/docker-compose.yml | 2 +- apix-docker/73/docker-compose.yml | 2 +- apix-docker/74/docker-compose.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apix-docker/70/docker-compose.yml b/apix-docker/70/docker-compose.yml index 1e4b188c..af551880 100644 --- a/apix-docker/70/docker-compose.yml +++ b/apix-docker/70/docker-compose.yml @@ -4,7 +4,7 @@ services: alfresco-core: image: ${DOCKER_IMAGE} ports: - - "${DOCKER_IP}::8080" + - "${DOCKER_IP}:8080:8080" volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped diff --git a/apix-docker/71/docker-compose.yml b/apix-docker/71/docker-compose.yml index 1e4b188c..af551880 100644 --- a/apix-docker/71/docker-compose.yml +++ b/apix-docker/71/docker-compose.yml @@ -4,7 +4,7 @@ services: alfresco-core: image: ${DOCKER_IMAGE} ports: - - "${DOCKER_IP}::8080" + - "${DOCKER_IP}:8080:8080" volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped diff --git a/apix-docker/72/docker-compose.yml b/apix-docker/72/docker-compose.yml index 1e4b188c..af551880 100644 --- a/apix-docker/72/docker-compose.yml +++ b/apix-docker/72/docker-compose.yml @@ -4,7 +4,7 @@ services: alfresco-core: image: ${DOCKER_IMAGE} ports: - - "${DOCKER_IP}::8080" + - "${DOCKER_IP}:8080:8080" volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped diff --git a/apix-docker/73/docker-compose.yml b/apix-docker/73/docker-compose.yml index 1c7a4894..1260a213 100644 --- a/apix-docker/73/docker-compose.yml +++ b/apix-docker/73/docker-compose.yml @@ -4,7 +4,7 @@ services: alfresco-core: image: ${DOCKER_IMAGE} ports: - - "${DOCKER_IP}::8080" + - "${DOCKER_IP}:8080:8080" volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped diff --git a/apix-docker/74/docker-compose.yml b/apix-docker/74/docker-compose.yml index 6c13c868..8e88c690 100644 --- a/apix-docker/74/docker-compose.yml +++ b/apix-docker/74/docker-compose.yml @@ -4,7 +4,7 @@ services: alfresco-core: image: ${DOCKER_IMAGE} ports: - - "${DOCKER_IP}::8080" + - "${DOCKER_IP}:8080:8080" volumes: - alfresco:/opt/alfresco/alf_data restart: unless-stopped From 4cb07d0bc96b90eaf5d8f6be8d705288b2bdc94c Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Thu, 30 Nov 2023 16:12:36 +0100 Subject: [PATCH 74/90] ALFREDAPI-527: Update CI badge in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 962fbc9b..4e7d9423 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Alfred API [![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) -[![Jenkins Build Status](https://jenkins-2.xenit.eu/buildStatus/icon?job=Xenit+Github%2Falfred-api%2Fmaster&subject=Jenkins)](https://jenkins-2.xenit.eu/job/Xenit%20Github/job/alfred-api/job/master/) +![CI status](https://github.com/xenit-eu/alfred-api/actions/workflows/ci.yml/badge.svg) [![Maven Central](https://img.shields.io/maven-central/v/eu.xenit.apix/apix-interface.svg)](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22eu.xenit.apix%22%20AND%20a%3A%22apix-interface%22) Alfred API abstracts away past and future changes to the Alfresco, across major and minor versions, providing a stable From 6a04bfd8ac47449bb0129673cf8625b22b35c8d0 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Thu, 30 Nov 2023 16:12:36 +0100 Subject: [PATCH 75/90] ALFREDAPI-527: Update Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89be94e5..c45d2dea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ This release also drop* support for Alfresco 6.2 and adds support for 7.4. * [ALFREDAPI-519](https://xenitsupport.jira.com/browse/ALFREDAPI-519): Add support for Alfresco 7.4 ### Changed +* [ALFREDAPI-527](https://xenitsupport.jira.com/browse/ALFREDAPI-527): +Alfresco containers use port 8080 now instead of ephemeral ports ### Fixed * [ALFREDAPI-520](https://xenitsupport.jira.com/browse/ALFREDAPI-520): Enforce encoding on bulk json responses to guarantee clean text From 813845757038895abab410c83f197fb5def29d66 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Mon, 4 Dec 2023 13:58:46 +0100 Subject: [PATCH 76/90] ALFREDAPI-519: Update Maven badge to alfred.api --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e7d9423..7dec3b60 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) ![CI status](https://github.com/xenit-eu/alfred-api/actions/workflows/ci.yml/badge.svg) -[![Maven Central](https://img.shields.io/maven-central/v/eu.xenit.apix/apix-interface.svg)](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22eu.xenit.apix%22%20AND%20a%3A%22apix-interface%22) +[![Maven Central](https://img.shields.io/maven-central/v/eu.xenit.alfred.api/apix-interface.svg)](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22eu.xenit.alfred.api%22%20AND%20a%3A%22apix-interface%22) Alfred API abstracts away past and future changes to the Alfresco, across major and minor versions, providing a stable interface to Alfresco on which client-side applications can be built. From 2b827fab2f0190df6dec24cd74c4586160ed9cf7 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Mon, 4 Dec 2023 16:21:23 +0100 Subject: [PATCH 77/90] ALFREDAPI-536: Move alfred-api-docs into this repo --- docs/README.md | 9 + docs/build-websites.sh | 83 ++ docs/docs/alfred-api/_hugo/config.yaml | 5 + .../src/main/java/DespecializeWebscript.java | 45 + .../src/main/java/jsonSearchQuery.java | 19 + .../examples/src/main/java/searchQuery.java | 73 ++ .../src/main/resources/jsonsearchquery.json | 83 ++ .../user/images/AlfredAPI-BackCover.jpg | Bin 0 -> 28644 bytes .../user/images/AlfredAPI-Footer-Logo.jpg | Bin 0 -> 23340 bytes .../user/images/AlfredAPI-FrontCover.jpg | Bin 0 -> 38188 bytes docs/docs/alfred-api/user/latex-h-break.lua | 21 + docs/docs/alfred-api/user/metadata.md | 25 + docs/docs/alfred-api/user/user-guide.md | 769 ++++++++++++++++++ 13 files changed, 1132 insertions(+) create mode 100644 docs/README.md create mode 100755 docs/build-websites.sh create mode 100644 docs/docs/alfred-api/_hugo/config.yaml create mode 100644 docs/docs/alfred-api/user/examples/src/main/java/DespecializeWebscript.java create mode 100644 docs/docs/alfred-api/user/examples/src/main/java/jsonSearchQuery.java create mode 100644 docs/docs/alfred-api/user/examples/src/main/java/searchQuery.java create mode 100644 docs/docs/alfred-api/user/examples/src/main/resources/jsonsearchquery.json create mode 100644 docs/docs/alfred-api/user/images/AlfredAPI-BackCover.jpg create mode 100644 docs/docs/alfred-api/user/images/AlfredAPI-Footer-Logo.jpg create mode 100644 docs/docs/alfred-api/user/images/AlfredAPI-FrontCover.jpg create mode 100644 docs/docs/alfred-api/user/latex-h-break.lua create mode 100644 docs/docs/alfred-api/user/metadata.md create mode 100644 docs/docs/alfred-api/user/user-guide.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..8b494685 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,9 @@ +# Documentation Alfred API + +## Generate website + +```bash +./build-websites.sh +``` + +This will generate a ZIP containing the documentation website. \ No newline at end of file diff --git a/docs/build-websites.sh b/docs/build-websites.sh new file mode 100755 index 00000000..4b690516 --- /dev/null +++ b/docs/build-websites.sh @@ -0,0 +1,83 @@ +#!/bin/bash +set -e +scriptPath="$( dirname "${BASH_SOURCE[0]}" )" # cd to the directory containing the script +cd "$scriptPath" + +MARKDOWNTOPDF_VERSION=v1.1.4 +MARKDOWNTOWEBSITE_VERSION=1.0.5 + +MARKDOWNTOPDF_IMAGE="private.docker.xenit.eu/xenit-markdowntopdf:$MARKDOWNTOPDF_VERSION" +MARKDOWN_SPLITTER_IMAGE="private.docker.xenit.eu/customer/xenit/xenit-manuals-markdown-splitter:$MARKDOWNTOWEBSITE_VERSION" +MANUALS_HUGO_GENERATOR_IMAGE="private.docker.xenit.eu/customer/xenit/xenit-manuals-hugo-generator:$MARKDOWNTOWEBSITE_VERSION" + +WEIGHT=0 + +build_manual() { + echo "Build manual $@" + local productName="$1" + local versionName="$2" + shift 2; + + mkdir -p "build/normalized/$productName" + tar c --portability -C "docs/$productName/$versionName" . | \ + docker run --rm -i $MARKDOWNTOPDF_IMAGE --tar \ + --template default -t markdown-simple_tables-multiline_tables-grid_tables --extract-media assets \ + --resource-path . \ + "$@" \ + -o normalized.md > "build/normalized/$productName/$versionName.tar" + sync +} + +split_manual() { + echo "Split manual $@" + local productName="$1" + local versionName="$2" + WEIGHT=$[$WEIGHT + 1] + mkdir -p "build/product/$productName" + tar tf "build/normalized/$productName/$versionName.tar" + cat "build/normalized/$productName/$versionName.tar" | docker run --rm -i $MARKDOWN_SPLITTER_IMAGE normalized.md "target-path=$versionName" "weight=$WEIGHT" > "build/normalized/$productName/$versionName-out.tar" + sync + tar xf "build/normalized/$productName/$versionName-out.tar" -C "build/product/$productName" +} + +build_and_split_manual() { + echo "Build & Split manual $@" + build_manual "$@" + split_manual "$1" "$2" +} + +build_product_website() { + local productName="$1" + mkdir -p "build/website/$productName" + cp -r "docs/$productName/_hugo" "build/product/$productName/_hugo" + tar c --portability -C "build/product/$productName" . | \ + docker run --rm -i $MANUALS_HUGO_GENERATOR_IMAGE | \ + tar x -C "build/website/$productName" + sync +} + +# Both Alfred API Javadoc and Swagger doc are built by the git submodule of the 'alfred-api' repository +build_alfredapi_javadoc() { + local alfredapidir="repo/alfred-api/stable" + pushd "$alfredapidir" + ./gradlew clean :apix-interface:javadoc + popd + + local outputdir="build/website/alfred-api/stable-user" + mkdir -p "$outputdir" + cp -a "$alfredapidir/apix-interface/build/docs/javadoc" $outputdir +} + +rm -rf build/ + +build_and_split_manual alfred-api user "user-guide.md" +build_product_website alfred-api +echo 40 +build_alfredapi_javadoc +echo 60 +echo 80 + +find build/website -type f -name '*.html' -print0 | xargs -0 sed -i "/^<\!DOCTYPE html>$/a\ +\<\!-- alfred-docs@$(git describe --always --dirty) --\>" + +tar czf build/website-alfred-api.tar.gz -C build/website . diff --git a/docs/docs/alfred-api/_hugo/config.yaml b/docs/docs/alfred-api/_hugo/config.yaml new file mode 100644 index 00000000..f37ceb10 --- /dev/null +++ b/docs/docs/alfred-api/_hugo/config.yaml @@ -0,0 +1,5 @@ +title: Alfred API +params: + metadata: + hugo-config: + product: api \ No newline at end of file diff --git a/docs/docs/alfred-api/user/examples/src/main/java/DespecializeWebscript.java b/docs/docs/alfred-api/user/examples/src/main/java/DespecializeWebscript.java new file mode 100644 index 00000000..95cd9fd8 --- /dev/null +++ b/docs/docs/alfred-api/user/examples/src/main/java/DespecializeWebscript.java @@ -0,0 +1,45 @@ +import eu.xenit.apix.data.NodeRef; +import eu.xenit.apix.data.QName; +import eu.xenit.apix.dictionary.IDictionaryService; +import eu.xenit.apix.dictionary.types.TypeDefinition; +import eu.xenit.apix.node.INodeService; +import eu.xenit.apix.node.MetadataChanges; +import eu.xenit.apix.node.NodeMetadata; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.DeclarativeWebScript; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptRequest; + +/** + * This webscript despecializes a node by converting it to its parent type and removing all properties that are + * specified by its current type + */ +public class DespecializeWebscript extends DeclarativeWebScript { + + private INodeService nodeService; + + private IDictionaryService dictionaryService; + + @Override + protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) { + NodeRef nodeRef = new NodeRef(req.getParameter("nodeRef")); + NodeMetadata metadata = nodeService.getMetadata(nodeRef); + TypeDefinition nodeType = dictionaryService.GetTypeDefinition(metadata.type); + MetadataChanges metadataChanges = new MetadataChanges(); + + Map newPropertyValues = new HashMap<>(); + for (QName property : nodeType.getProperties()) { + String[] strings = {}; + newPropertyValues.put(property, strings); + } + metadataChanges.setPropertiesToSet(newPropertyValues); + metadataChanges.setType(nodeType.getParent()); + + nodeService.setMetadata(nodeRef, metadataChanges); + + return Collections.emptyMap(); + } +} diff --git a/docs/docs/alfred-api/user/examples/src/main/java/jsonSearchQuery.java b/docs/docs/alfred-api/user/examples/src/main/java/jsonSearchQuery.java new file mode 100644 index 00000000..0616b371 --- /dev/null +++ b/docs/docs/alfred-api/user/examples/src/main/java/jsonSearchQuery.java @@ -0,0 +1,19 @@ +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; +import eu.xenit.apix.search.SearchQuery; +import eu.xenit.apix.search.json.SearchNodeJsonParser; +import eu.xenit.apix.search.visitors.SearchSyntaxPrinter; +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; + +class jsonSearchQuery { + + public static void main(String[] argv) throws IOException, URISyntaxException { + InputStream inputStream = jsonSearchQuery.class.getResourceAsStream("jsonsearchquery.json"); + ObjectMapper mapper = new SearchNodeJsonParser().getObjectMapper(); + mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); + SearchQuery searchQuery = mapper.readValue(inputStream, SearchQuery.class); + System.out.println(SearchSyntaxPrinter.Print(searchQuery.getQuery())); + } +} diff --git a/docs/docs/alfred-api/user/examples/src/main/java/searchQuery.java b/docs/docs/alfred-api/user/examples/src/main/java/searchQuery.java new file mode 100644 index 00000000..65eaa02f --- /dev/null +++ b/docs/docs/alfred-api/user/examples/src/main/java/searchQuery.java @@ -0,0 +1,73 @@ +//\ifdef{EXAMPLE_IMPORTS}Imports + +import eu.xenit.apix.data.QName; +import eu.xenit.apix.data.StoreRef; +import eu.xenit.apix.search.QueryBuilder; +import eu.xenit.apix.search.SearchQuery; +import eu.xenit.apix.search.SearchQueryConsistency; +import eu.xenit.apix.search.nodes.SearchSyntaxNode; +import eu.xenit.apix.search.visitors.SearchSyntaxPrinter; +import java.io.IOException; +import java.util.Arrays; + +// \endif \if{0} +class searchQuery { + + public static void main(String[] argv) throws IOException { +//\endif\ifdef{EXAMPLE_SEARCH_QUERY_OPTS}Setting search query options + SearchQuery searchQuery = new SearchQuery(); + searchQuery.getPaging().setSkip(10); // Skip the first 10 results + searchQuery.getPaging().setLimit( + 25); // Return maximum 25 results in response to the query. It defaults to 25 results, set to -1 for unlimited results + + searchQuery.getFacets().setEnabled(true); // Enables faceting + searchQuery.getFacets().setMincount(10); // Show only facet values with a minimum of 10 items matching the facet + searchQuery.getFacets().setLimit(10); // Show only the top 10 facet values for each facet + // searchQuery.setWorkspace("workspace-protocol://workspace-identifier"); // Optional parameter, defaults to "workspace://SpacesStore" + // e.g. searchQuery.setWorkspace(new StoreRef("archive://SpacesStore")); // To search in deleted nodes + + searchQuery.setOrderBy(Arrays.asList( + new SearchQuery.OrderBy( + SearchQuery.OrderBy.Order.ASCENDING, + new QName("{http://www.alfresco.org/model/content/1.0}modifier") + ), // Order by cm:modifier ascending + new SearchQuery.OrderBy( + SearchQuery.OrderBy.Order.DESCENDING, + new QName("{http://www.alfresco.org/model/content/1.0}creator") + ) // Then order by cm:creator descending + )); + +// Set search query consistency to transactional (defaults to eventual consistency) + searchQuery.setConsistency(SearchQueryConsistency.TRANSACTIONAL); +// searchQuery.setConsistency(SearchQueryConsistency.EVENTUAL); +// \endif\ifdef{EXAMPLE_SEARCH_QUERY_QUERY}Building the search query + QueryBuilder queryBuilder = new QueryBuilder(); + SearchSyntaxNode query = queryBuilder + .startAnd() + .property("{http://www.alfresco.org/model/content/1.0}creator", "admin", + true) // Search for cm:creator = admin with an exact match + .startOr() + .property("{http://www.alfresco.org/model/content/1.0}created", "2015-01-01T00:00:00+00:00", + "2020-08-16T00:00:00+00:00") // Date range query + .property("{http://www.alfresco.org/model/content/1.0}modified", "2015-01-01T00:00:00+00:00", + "2020-08-16T00:00:00+00:00") + .end() + .not().term("aspect", + "{http://www.alfresco.org/model/system/1.0}hidden") // Possible terms: "type", "aspect", "noderef", "path", "text", "parent", "category", "all" + .term("type", "{http://www.alfresco.org/model/content/1.0}document") + .term("path", "/app:company_home/app:shared/*") // All documents in the folder + .term("path", "/app:company_home/app:shared//*") // All documents in the folder and subfolders + .term("path", "/app:company_home/app:shared/") // Folder itself + .term("parent", + "workspace://SpacesStore/c4ebd508-b9e3-4c48-9e93-cdd774af8bbc") // All direct children of this noderef + .term("text", "xenit solutions") // Full text search + .term("all", "banana") // Search in full text, cm:name, cm:author, cm:creator, cm:modifier + .end() + .create(); + searchQuery.setQuery(query); +// FTS Query: cm:creator:"admin" AND (cm:created:"2015-01-01T00:00:00+00:00".."2020-08-16T00:00:00+00:00" OR cm:modified:"2015-01-01T00:00:00+00:00".."2020-08-16T00:00:00+00:00") AND NOT ASPECT:"sys:hidden" +// \endif \if{0} + System.out.println(SearchSyntaxPrinter.Print(query)); + } +} +// \endif diff --git a/docs/docs/alfred-api/user/examples/src/main/resources/jsonsearchquery.json b/docs/docs/alfred-api/user/examples/src/main/resources/jsonsearchquery.json new file mode 100644 index 00000000..ec6bcf2d --- /dev/null +++ b/docs/docs/alfred-api/user/examples/src/main/resources/jsonsearchquery.json @@ -0,0 +1,83 @@ +{ + "query": { + "and": [ + { + "property": { + "name": "{http://www.alfresco.org/model/content/1.0}creator", + "value": "admin" + } + }, + { + "or": [ + { + "property": { + "name": "{http://www.alfresco.org/model/content/1.0}created", + "range": { + "start": "2015-01-01T00:00:00+00:00", + "end": "2020-08-16T00:00:00+00:00" + } + } + }, + { + "property": { + "name": "{http://www.alfresco.org/model/content/1.0}modified", + "range": { + "start": "2015-01-01T00:00:00+00:00", + "end": "2020-08-16T00:00:00+00:00" + } + } + } + ] + }, + { + "not": { + "aspect": "{http://www.alfresco.org/model/system/1.0}hidden" + } + }, + { + "type": "{http://www.alfresco.org/model/content/1.0}document" + }, + { + "path": "/app:company_home/app:shared/*" + }, + { + "path": "/app:company_home/app:shared//*" + }, + { + "path": "/app:company_home/app:shared/" + }, + { + "parent": "workspace://SpacesStore/c4ebd508-b9e3-4c48-9e93-cdd774af8bbc" + }, + { + "text": "xenit solutions" + }, + { + "all": "banana" + } + ] + }, + "paging": { + "skip": 10, + "limit": 25 + }, + "facets": { + "enabled": true, + "mincount": 10, + "limit": 10 + }, + "orderBy": [ + { + "property": "{http://www.alfresco.org/model/content/1.0}modifier", + "order": "ascending" + }, + { + "property": "{http://www.alfresco.org/model/content/1.0}creator", + "order": "ascending" + } + ], + "consistency": "TRANSACTIONAL" // or "EVENTUAL", + "workspace": { // optional. default value workspace://SpacesStore + "value": "workspace://SpacesStore" // or any other e.g. archive://SpacesStore" + } +} \ No newline at end of file diff --git a/docs/docs/alfred-api/user/images/AlfredAPI-BackCover.jpg b/docs/docs/alfred-api/user/images/AlfredAPI-BackCover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bd03dfa8212f8a8f073677edece189901666dec6 GIT binary patch literal 28644 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 literal 0 HcmV?d00001 diff --git a/docs/docs/alfred-api/user/images/AlfredAPI-Footer-Logo.jpg b/docs/docs/alfred-api/user/images/AlfredAPI-Footer-Logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3a89bc59e5f84775043daf98e3e6ba6ad109c4b8 GIT binary patch literal 23340 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

e)3Zac)~!KnW)^_Sb}!idB|I6>UpRH_#lm;*?l% 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 literal 0 HcmV?d00001 diff --git a/docs/docs/alfred-api/user/latex-h-break.lua b/docs/docs/alfred-api/user/latex-h-break.lua new file mode 100644 index 00000000..658da166 --- /dev/null +++ b/docs/docs/alfred-api/user/latex-h-break.lua @@ -0,0 +1,21 @@ +--[======================================================================[ + +latex-h-break.lua - Pandoc filter to get break after a level 4 or higher heading. +See https://stackoverflow.com/questions/21198025/pandoc-generation-of-pdf-from-markdown-4th-header-is-rendered-differently + +Usage: + + $ pandoc --lua-filter latex-h-break.lua input.md -o output.pdf + +--]======================================================================] + +-- create it once, use it many times! +local hfill_block = pandoc.RawBlock('latex', '\\hfill') + +function Header (elem) + if 3 < elem.level then + return { elem, hfill_block } + else -- ignore headings at other levels! + return nil + end +end \ No newline at end of file diff --git a/docs/docs/alfred-api/user/metadata.md b/docs/docs/alfred-api/user/metadata.md new file mode 100644 index 00000000..653eeffd --- /dev/null +++ b/docs/docs/alfred-api/user/metadata.md @@ -0,0 +1,25 @@ +--- +title: + - Alfred API + - User Guide +date: 17/01/2023 +document-reference: Alfred API/User Guide +document-revision: 0.1 +copyright-year: 2020-2023 + +product-color: 33a89f +frontpage-background-img: images/AlfredAPI-FrontCover.jpg +backcover-background-img: images/AlfredAPI-BackCover.jpg +footer-img: images/AlfredAPI-Footer-Logo.jpg + +pandoc-args: + template: manual + +tables: true +numbersections: true +secnumdepth: 7 +toc: true +toc-depth: 7 +fontawesome: true + +--- diff --git a/docs/docs/alfred-api/user/user-guide.md b/docs/docs/alfred-api/user/user-guide.md new file mode 100644 index 00000000..92468335 --- /dev/null +++ b/docs/docs/alfred-api/user/user-guide.md @@ -0,0 +1,769 @@ +\include{metadata.md} + +# About +Alfred API abstracts away past and future changes to the Alfresco, across major and minor +versions, providing a stable interface to Alfresco on which client-side applications can be built. + +It also provides functional grouping of related operations from the Alfresco Public API, +and additional endpoints that are not supported by the Alfresco Public API. + + +# Alfred API Concepts +Alfred API is composed of two logical layers. + +* The base layer is a *Java API* built on top of the Alfresco. +* A *REST API* is built on top of the Java abstraction layer, exposing a stable HTTP API. + +Instead of mirroring the Alfresco API one-to-one, Alfred API groups frequently used operations +together in a single method call. This allows you to focus on business concerns instead of focusing +on fetching all required data from Alfresco. + +For example, the `NodeService.getMetadata()` method returns an object with all metadata about +a node: its type, aspects and properties in a single function call. It groups together the +information that would otherwise have to be obtained by combining requests for type, aspects +and properties separately. + +## Data objects +Alfred API has data objects that mirror the Alfresco concepts of QName, NodeRef, StoreRef, Path, +ContentData and ContentInputStream. These data objects are used to communicate with the +Alfred Java API without being dependent on Alfresco data types. + +Conversion between Alfresco and Alfred API data objects is the responsibility of the +`ApixToAlfrescoConversion` service. It is also possible to construct an Alfred API data object by +passing its string representation to the constructor. + + +# Java API +The Java API is the core to exposing Alfresco functionality and normalizing operations across version. +Any extensions written while depending on Alfred API can be easily ported to a new Alfresco version. + +When the API is installed, all of its service are available as beans and can be wired into your own classes. + +## Services +Only the most important services are described below. Full documentation is available in +[the generated JavaDoc](https://docs.xenit.eu/alfred-api/stable-user/javadoc/). + +### NodeService +The `NodeService` provides operations on nodes. + +* Fetch and modify the metadata for a Node +* Fetch the root node of a Store +* Fetch, create and remove child, parent and target associations for a Node +* Copy or move a Node to another parent +* Create and delete Nodes +* Checkout, checkin and fetch working copies for a Node + +### SearchService +The `SearchService` allows searching for nodes based on an object tree. + +The `SearchService.query()` method takes a `SearchQuery` object which contains the search query to execute, +as well as pagination, faceting and ordering options. + +\define{EXAMPLE_IMPORTS} +\define{EXAMPLE_SEARCH_QUERY_OPTS} +```java +\include{examples/src/main/java/searchQuery.java} +``` +\undef{EXAMPLE_IMPORTS} +\undef{EXAMPLE_SEARCH_QUERY_OPTS} + +The query itself can be constructed using the `QueryBuilder`, which provides a fluent interface to +build search queries. + +\define{EXAMPLE_SEARCH_QUERY_QUERY} +```java +\include{examples/src/main/java/searchQuery.java} +``` +\undef{EXAMPLE_SEARCH_QUERY_QUERY} + +When using the REST API, a JSON payload describing the search query has to be POST'ed to the +`apix/v1/search` endpoint. +This JSON document reflects the node structure created by the query builder, and is shown below: + +```json +\include{examples/src/main/resources/jsonsearchquery.json} +``` + +### DictionaryService +The `DictionaryService` provides meta-information about the metadata model. +It allows to fetch information about registered types, aspect and properties. + + +# REST API +The Alfred REST API is a thin wrapper around the Java abstraction layer. It converts its received +parameters to the corresponding Alfred API data objects, then calls the corresponding service and +serializes its return value to JSON. + +For a full overview of the REST API, please refer to +[the swagger specification](https://docs.xenit.eu/alfred-api/stable-user/swagger-ui/). + + +## Search Requests + +### Query +Object containing subcomponents that build the requested query. +All queries are translated to Alfresco Full Text Search (see +[AFTS](https://community.alfresco.com/docs/DOC-5729-full-text-search-query-syntax)) by Alfred API when executed. + + +#### Syntax + +The query parameter takes a tree structure of search nodes as its argument. +A search node is either an operator, or a search term. + +##### Operators + +Operators currently include only the standard `AND`, `OR` and `NOT` logical operations. +An operator is structured in the JSON payload as a named list. + +* And + +Translating `cm:name:"Budget 2020.xls" AND example:customProperty:"#AA3BF5"` +```json +{ + "and": [ + { + "property" : { + "name": "cm:name", + "value": "Budget 2020.xls" + } + }, + { + "property" : { + "name" : "example:customProperty", + "value" : "#AA3BF5" + } + } + ] +} +``` + +* Or + +Translating `example:customProperty:"#FFF233" OR example:customProperty:"#AA3BF5"` +```json +{ + "or": [ + { + "property" : { + "name" : "example:customProperty", + "value" : "#FFF233" + } + }, + { + "property" : { + "name" : "example:customProperty", + "value" : "#AA3BF5" + } + } + ] +} +``` + +* Not + +Translating `NOT cm:name:"Budget 2020.xls"` +```json +{ + "not": { + "property": { + "name": "cm:name", + "value": "Budget 2020.xls" + } + } +} +``` + +* Nesting + +Operators can be nested to form complex queries: +```json +{ + "and" : [ + { + "not": { + "property" : { + "name" : "example:customProperty", + "value" : "#FFF233" + } + } + }, + { + "or": [ + { + "property" : { + "name" : "example:customProperty", + "value" : "#FFF233" + } + }, + { + "property" : { + "name" : "example:customProperty", + "value" : "#AA3BF5" + } + } + ] + } + ] +} +``` +##### Search terms + +Search terms can be split into two groups: special terms and generic terms. +Special terms are used to search for specific concepts, generic terms are used to search for property values at large. + +**Special terms** + +* type + +`Supports transactional metadata queries` + +Lookup for any nodes of the given contentmodel type. +```json +{ "type": "cm:folder" } +``` + + +* aspect + +`Supports transactional metadata queries` + +Lookup for any nodes which have the give aspect. +```json +{ "aspect": "sys:folder"} +``` + + +* noderef + +`Supports transactional metadata queries` + +Lookup for a specific Alfresco noderef. +```json +{ "noderef": "workspace://SpacesStore/c4ebd508-b9e3-4c48-9e93-cdd774af8bbc" } +``` + + +* path + +`Supports transactional metadata queries` + +Lookup for nodes at the given XPath. +```json +{ "path": "/app:company_home/cm:Fred_x0020_Performance_x0020_Test/*" } +``` + + +* parent + +`Supports transactional metadata queries` + +Lookup for any nodes with the given node as parent. Takes a noderef as argument. +```json +{ "parent": "workspace://SpacesStore/c4ebd508-b9e3-4c48-9e93-cdd774af8bbc" } +``` + +* text + +Lookup for any nodes that have given text in their content. Requires content of nodes to be indexed by Solr to be found. +```json +{ "text": "xenit solutions" } +``` + +* category + +Lookup for any nodes are of the given category. +```json +{ "category": "/cm:generalclassifiable/cm:Software_x0020_Document_x0020_Classification/member" } +``` + +* all + +Lookup for any nodes with a hit for the searchterm in any field or in the content. +```json +{ "all": "Xenit solutions"} +``` + +* isunset + +Lookup for any nodes where the value of given propety is not set. +```json +{ "isunset": "cm:author"} +``` + +* exists + +Lookup for any nodes where the given property is present. +```json +{ "exists": "cm:author" } +``` + +* isnull + +Lookup for any nodes where the value of the given property is set to null. +```json +{ "isnull": "cm:author"} +``` + +* isnotnull + +Lookup for any nodes where the value of the given property is set and not null. +```json +{ "isnotnull": "cm:author" } +``` + +**Unsupported terms** + +The following terms are available in Alfresco, but are currently not supported by Alfred API: + +* isroot +* tx +* primaryparent +* class +* exactclass +* qname +* exactaspect +* tag + + +**Generic terms** + +Generic terms are search terms for any given property with any given value or range. +```json +{ "property": + { + "name": "example:customProperty", + "value": "som*value" + } +} +``` +```json +{ "property": + { + "name":"cm:modified", + "range":{ + "start":"2015-10-05T10:41:42+00:00", + "end":"2020-02-25T09:36:01+00:00" + } + } +} +``` +Terms using values can also take the `exact` boolean parameter (by default it is considered set to false). +This signifies that the given value needs to be matched exactly, as opposed to the default fuzzy search. +This also implies that wildcards are not compatible with the exact parameter. + +**For Transactional Metadata Queries, the `exact` parameter is mandatory.** +```json +{ "property": + { + "name": "example:customProperty", + "value": "som*value", + "exact": true + } +} +``` + +### paging + +`Optional` + +Options to page through the search results by setting a skipcount and a page size limit. +```json +{ + "paging": { + "limit": 10, + "skip": 0 + } +} +``` + +### facets + +`Optional` + +Options to enable facets. This will return facet results as configured on the server. +The Alfresco `limit` and `minCount` parameters are not implemented. + +**Note:** facets with 0 hits are not returned in the result +```json +{ + "facets": { + "enabled": true + } +} +``` + + +### orderBy + +`Optional` + +Options to define a list of properties to order by and the direction of ordering per property. +Expression based sorting is not implemented. +```json +{ + "orderBy": [ + { + "property": "cm:name", + "order": "descending" + }, + { + "property": "cm:modified", + "order": "ascending" + } + ] +} +``` + +### consistency + +`Optional` + +Option to request specific consistency. Options are: + +* `EVENTUAL` +* `TRANSACTIONAL` +* `TRANSACTIONAL_IF_POSSIBLE` (default) +```json +{ + "consistency": "TRANSACTIONAL" +} +``` + +#### Note on search, consistency and fuzziness + +Alfresco internally supports two types of search queries: database-backed and Solr-backed. Based on the server configuration +and the search query, it will determine which of these 2 to use. Alfresco will attempt to use the database, but for any query +on indexed properties, content or for fuzzy matching, Solr is required. + +In the documentation database-backed queries are known as `Transactional Metadata Queries` or `TDMQ`'s. +To enable TDMQ's for Alfred API the `exact` parameter is required for generic search terms to be searched in the database, +and from the special search terms, only a subset is available for use. See the search term section + +The other search, Solr-backed, allows the usage of wild cards and other forms of fuzziness, but requires the Solr component +to build indexes against the Alfresco repository. This means that some time and resources are spent to bring the search index +up to date with the repository. As a consequence, after any given change, a window of time exists where a searchrequest against +Solr will return a result inconsistent with the repo. This effect will pass with time, hence the name eventual consistency. + +### locale + +`Optional` + +Options to request specific locale and encoding options. +```json +{ + "locale": "BE" +} +``` + +### workspace + +`Optional` + +Options to change the target Alfresco workspace. This would allow searches on the archive or on custom workspaces. +A workspace is in this context defined by the `workspace name` + the protocol delimiter `://` + `the target store name`. + +**Note**: if the target store is not indexed by Solr, eventually consistent queries will result in errors. +```json +{ + "workspace": "archive://SpacesStore" +} +``` + +### highlight + +`Optional` + +Options to change the highlight configuration. +Minimal requirement is the `fields` array, which takes object containing at least the `field` property. +Each list element specifies a property on which higlighting needs to be applied. +When no fields are specified, the call defaults to `cm:content` as field. +Full documentation can be found on the Alfresco documentation page: + +* [7.0](https://docs.alfresco.com/content-services/7.0/develop/rest-api-guide/searching/#term-highlighting-search) +* [7.1](https://docs.alfresco.com/content-services/7.1/develop/rest-api-guide/searching/#term-highlighting-search) +* [7.2](https://docs.alfresco.com/content-services/7.2/develop/rest-api-guide/searching/#term-highlighting-search) +* [7.3](https://docs.alfresco.com/content-services/7.3/develop/rest-api-guide/searching/#term-highlighting-search) +* [7.4](https://docs.alfresco.com/content-services/7.4/develop/rest-api-guide/searching/#term-highlighting-search) + +```json +{ + "highlights": + { + "prefix": "", + "postfix": "", + "snippetCount": 2, + "fields": [ + { + "field": "cm:content" + } + ] + } +} +``` + +### Example Search Queries + +Search for the first 10 nodes in the `cm:content` namespace with facets: +```json +{ + "query": {"type":"{http://www.alfresco.org/model/content/1.0}content"}, + "paging": { + "limit": 10, + "skip": 0 + }, + "facets": { + "enabled": false + } +} +``` + +Search for all nodes with the term 'budget' in the `cm:content` property (fulltext), and show two highlighted hits with +delimiter \\\\: +```json +{ + "query": { + "property": { + "exact": false, + "name": "cm:content", + "value": "budget" + } + }, + "highlight":{ + "prefix":"", + "postfix":"", + "snippetCount":2, + "fields":[{"field":"cm:content"}] + } +} +``` + +### JSON response + +The search REST call returns a JSON object of the following form: +```json +{ + "noderefs": [ // List of noderefs + "workspace://SpacesStore/c4ebd508-b9e3-4c48-9e93-cdd774af8bbc", + "workspace://SpacesStore/ff5874ad-b9e3-4c48-9e93-cddaaa9746ec" + ], + "facets": [ // list of facets + { + "name": "TYPE", // facet field name + "values": [ // Facet values + { + "value": "Factuur", + "label": "Factuur", + "count": 16 + } + ] + }, + { + "name": "cm:modified", // facet field name + "values": [ // Facet values + { + "range": + { + "start":"2020-05-01T00:00:00+00:00", + "end":"2020-05-31T00:00:00+00:00" + }, + "label": "One month ago", + "count": 16 // value and count + } + ] + } + ], + "totalResultCount": 2, //Sum of all results + "highlights": { + "noderefs": { //A set of objects with an entry for each noderef for which a highlight can be returned + "workspace://SpacesStore/e818fd1c-262e-43f1-8751-461cd8de9293": [ //list of highlights per specified field for the given node + { + "field": "cm:name", + "snippets": [ + "Stretch your research budget-20150813-155144.msg" + ] + } + ] + } + } +} +``` + +### Additional notes + +#### Date format + +Dates and times must be specified in [ISO-8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. + +#### Unimplemented search options: +These options have some code towards handling, but are not implemented such that they are used in the search. + +* `facets.mincount` +* `facets.limit` +* `orderBy.expression` + + +## Usage Example + +In this example a new node will be created and its metadata set: + +**1.** Find the default Alfresco folder named "Shared" to use as parent folder for the new node. +```bash +curl -X POST \ +--header "Authorization: Basic a8d46fw84649" \ +--header "Accepts: application/json" \ +--header "Content-Type: application/json" \ +--data '{ "query": { "property": { "name":"cm:name", "value":"Shared", "exact": true } } }' \ +https://www.alfresco.example/alfresco/s/apix/v1/search +``` +Response: +```json +{ + "noderefs": [ "workspace://SpacesStore/df18bcde-531b-4b39-9698-e460cbff2bb5" ], + "totalResultCount": 1 +} +``` +**2.** Create the new node +```bash +curl -X POST \ +--header "Authorization: Basic a8d46fw84649" \ +--header "Content-Type: application/json" \ +--data '{ "parent": "workspace://SpacesStore/df18bcde-531b-4b39-9698-e460cbff2bb5", "name": "Red test node", "type": "{http://www.alfresco.org/model/content/1.0}content" }' \ +https://www.alfresco.example/alfresco/s/apix/v1/nodes +``` +Response: +```json +{ + "noderef":"workspace://SpacesStore/d26176d6-11d9-4381-a327-cccb7600efc4", + "metadata": { + "id":"workspace://SpacesStore/d26176d6-11d9-4381-a327-cccb7600efc4", + "type":"{http://www.alfresco.org/model/content/1.0}content", + "baseType":"{http://www.alfresco.org/model/content/1.0}content", + "transactionId":66261, + "properties": { + "{http://www.alfresco.org/model/system/1.0}store-protocol":["workspace"], + "{http://www.alfresco.org/model/system/1.0}node-dbid":["128993"], + "{http://www.alfresco.org/model/content/1.0}name":["Red test node"], + "{http://www.alfresco.org/model/content/1.0}modified":["2020-10-06T12:31:12.356Z"], + "{http://www.alfresco.org/model/content/1.0}creator":["admin"], + "{http://www.alfresco.org/model/system/1.0}locale":["en_US"], + "{http://www.alfresco.org/model/content/1.0}created":["2020-10-06T12:31:12.356Z"], + "{http://www.alfresco.org/model/system/1.0}store-identifier":["SpacesStore"], + "{http://www.alfresco.org/model/content/1.0}modifier":["admin"], + "{http://www.alfresco.org/model/system/1.0}node-uuid":["d26176d6-11d9-4381-a327-cccb7600efc4"], + }, + "aspects":[ + "{http://www.alfresco.org/model/content/1.0}auditable", + "{http://www.alfresco.org/model/system/1.0}referenceable", + "{http://www.alfresco.org/model/system/1.0}localized" + ] + }, + "permissions": { + "Read":"ALLOW", + "Write":"ALLOW", + "Delete":"ALLOW", + "AddChildren":"ALLOW", + "ReadPermissions":"ALLOW", + "ReadRecords":"DENY", + "Filing":"DENY", + "CreateChildren":"ALLOW", + "ChangePermissions":"ALLOW", + }, + "associations":{ + "children":[], + "parents":[ + { + "source":"workspace://SpacesStore/d26176d6-11d9-4381-a327-cccb7600efc4", + "target":"workspace://SpacesStore/df18bcde-531b-4b39-9698-e460cbff2bb5", + "type":"{http://www.alfresco.org/model/content/1.0}contains", + "primary":true + } + ], + "targets":[] + }, + "path":{ + "displayPath":"/Company Home/Shared", + "qnamePath":"/app:company_home/app:shared/cm:Red_x0020_test_x0020_node" + } +} +``` + +## REST HTTP result codes +REST responses can return the following HTTP status codes: + + +### 2xx Success + +Indicates request sent by client was understood and accepted. + +* **200 OK**: Generic success. +* **202 Accepted**: The request was successful and will be processed asynchronously. +* **207 Multi-Status**: A bulk request completed successfully. These responses should contain multi-status response that + can be correlated to each individual request in the bulk request. Can be returned even if individual requests fail. + + +### 3xx Redirection + +Indicates the client must take additional steps to complete the request. + +* **301 Moved Permanently**: This and all future requests should be directed to the given URI. + + +### 4xx Client error + +Indicates anticipated failures, such as requests for non-existant resources, +requests with missing input and malformed requests. + +A body *may* be provided in the response that clarifies the error. + +* **400 Bad Request**: Generic client error. +* **401 Unauthorized**: User must log in. +* **403 Forbidden**: User not authorized to use this resource. +* **404 Not Found**: Requested resource not found. Returned also for e.g. requesting a node with an incorrect id, as + well as unhandled URI's. For security reasons, a 404 can aso be returned when the requester has insufficient permissions. +* **405 Method Not Allowed**: A request method is not supported (e.g. PUT on an endpoint that only accepts GET). + + +### 5xx Server error + +Indicates unexpected failures. + +* **500 Internal Server Error**: Generic server error. +* **503 Service Unavailable**: Temporary server error. Retry later is sensible. + +# Installation + +## Supported Alfresco versions +Currently Alfred API supports the following Alfresco versions: + +* 7.0 +* 7.1 +* 7.2 +* 7.3 +* 7.4 + +Note that previous versions of Alfred API needed +[Dynamic Extensions For Alfresco](https://github.com/xenit-eu/dynamic-extensions-for-alfresco). +Since version 5.0.0, however, Dynamic Extensions is no longer needed. + +## Artifacts +### Prebuilt +Artifacts can be freely obtained through [Maven Central](https://search.maven.org/search?q=g:eu.xenit.apix). +The application is available as an Alfresco AMP artifact, which is the preferred distribution for production environments. + +To install the AMP, follow the Alfresco AMP installation guidelines your version of Alfresco: + +* [7.0](https://docs.alfresco.com/content-services/7.0/install/zip/amp/) +* [7.1](https://docs.alfresco.com/content-services/7.1/install/zip/amp/) +* [7.2](https://docs.alfresco.com/content-services/7.2/install/zip/amp/) +* [7.3](https://docs.alfresco.com/content-services/7.3/install/zip/amp/) +* [7.4](https://docs.alfresco.com/content-services/7.4/install/zip/amp/) + +# Contributing +Alfred API is open source. The code is available from [Github](https://github.com/xenit-eu/alfred-api). Building the artifacts requires +access to Alfresco Enterprise libraries to satisfy Enterprise dependencies. + +If you wish to contribute, please refer to the [README.md](https://github.com/xenit-eu/alfred-api/blob/master/README.md) +in its code repository. + +Note: For legacy reasons the older name `apix` can still be found in certain locations. From 95dfbf119e3601c6866dbbbfb3706c8aa0d4aad3 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Mon, 4 Dec 2023 16:21:23 +0100 Subject: [PATCH 78/90] ALFREDAPI-536: Fix dirs in docs script --- docs/build-websites.sh | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/docs/build-websites.sh b/docs/build-websites.sh index 4b690516..2cb4c8d1 100755 --- a/docs/build-websites.sh +++ b/docs/build-websites.sh @@ -13,7 +13,7 @@ MANUALS_HUGO_GENERATOR_IMAGE="private.docker.xenit.eu/customer/xenit/xenit-manua WEIGHT=0 build_manual() { - echo "Build manual $@" + echo "===== Building manual =====" local productName="$1" local versionName="$2" shift 2; @@ -29,7 +29,7 @@ build_manual() { } split_manual() { - echo "Split manual $@" + echo "===== Splitting manual =====" local productName="$1" local versionName="$2" WEIGHT=$[$WEIGHT + 1] @@ -41,12 +41,12 @@ split_manual() { } build_and_split_manual() { - echo "Build & Split manual $@" build_manual "$@" split_manual "$1" "$2" } build_product_website() { + echo "===== Building website =====" local productName="$1" mkdir -p "build/website/$productName" cp -r "docs/$productName/_hugo" "build/product/$productName/_hugo" @@ -58,26 +58,25 @@ build_product_website() { # Both Alfred API Javadoc and Swagger doc are built by the git submodule of the 'alfred-api' repository build_alfredapi_javadoc() { - local alfredapidir="repo/alfred-api/stable" + echo "===== Generating javadoc =====" + local productName="$1" + local versionName="$2" + local alfredapidir=".." + pushd "$alfredapidir" ./gradlew clean :apix-interface:javadoc popd - local outputdir="build/website/alfred-api/stable-user" + local outputdir="build/website/$productName/$versionName" mkdir -p "$outputdir" cp -a "$alfredapidir/apix-interface/build/docs/javadoc" $outputdir } rm -rf build/ - build_and_split_manual alfred-api user "user-guide.md" build_product_website alfred-api -echo 40 -build_alfredapi_javadoc -echo 60 -echo 80 +build_alfredapi_javadoc alfred-api user find build/website -type f -name '*.html' -print0 | xargs -0 sed -i "/^<\!DOCTYPE html>$/a\ \<\!-- alfred-docs@$(git describe --always --dirty) --\>" - tar czf build/website-alfred-api.tar.gz -C build/website . From 7581c676a6b8510adf49b459be49120f5d422a60 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Mon, 4 Dec 2023 16:21:23 +0100 Subject: [PATCH 79/90] ALFREDAPI-536: Rename to build-website.sh --- docs/README.md | 8 ++++++-- docs/{build-websites.sh => build-website.sh} | 0 2 files changed, 6 insertions(+), 2 deletions(-) rename docs/{build-websites.sh => build-website.sh} (100%) diff --git a/docs/README.md b/docs/README.md index 8b494685..142113c8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,8 +2,12 @@ ## Generate website +This directory generates the product documentation website at https://docs.xenit.eu/alfred-api/ + +This is done by manually executing: ```bash -./build-websites.sh +./build-website.sh ``` -This will generate a ZIP containing the documentation website. \ No newline at end of file +This will generate a ZIP containing the documentation website, which still needs to be +uploaded and unzipped on our host. \ No newline at end of file diff --git a/docs/build-websites.sh b/docs/build-website.sh similarity index 100% rename from docs/build-websites.sh rename to docs/build-website.sh From 1aa9999e2df92b4b80659531457e83adfe65d730 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Mon, 4 Dec 2023 16:21:23 +0100 Subject: [PATCH 80/90] ALFREDAPI-536: Update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c45d2dea..645a1820 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,8 @@ This release also drop* support for Alfresco 6.2 and adds support for 7.4. ### Changed * [ALFREDAPI-527](https://xenitsupport.jira.com/browse/ALFREDAPI-527): -Alfresco containers use port 8080 now instead of ephemeral ports +Alfresco containers use port 8080 now instead of ephemeral ports +* [ALFREDAPI-536](https://xenitsupport.jira.com/browse/ALFREDAPI-536): Reabsorb alfred-api-docs repo into this ### Fixed * [ALFREDAPI-520](https://xenitsupport.jira.com/browse/ALFREDAPI-520): Enforce encoding on bulk json responses to guarantee clean text From 08edce3600004ce64cf163277579681899fb1b69 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Mon, 4 Dec 2023 16:21:23 +0100 Subject: [PATCH 81/90] ALFREDAPI-536: Update Maven link with new group id --- docs/docs/alfred-api/user/user-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/alfred-api/user/user-guide.md b/docs/docs/alfred-api/user/user-guide.md index 92468335..fae3444c 100644 --- a/docs/docs/alfred-api/user/user-guide.md +++ b/docs/docs/alfred-api/user/user-guide.md @@ -748,7 +748,7 @@ Since version 5.0.0, however, Dynamic Extensions is no longer needed. ## Artifacts ### Prebuilt -Artifacts can be freely obtained through [Maven Central](https://search.maven.org/search?q=g:eu.xenit.apix). +Artifacts can be freely obtained through [Maven Central](https://search.maven.org/search?q=g:eu.xenit.alfred.api). The application is available as an Alfresco AMP artifact, which is the preferred distribution for production environments. To install the AMP, follow the Alfresco AMP installation guidelines your version of Alfresco: From 926e553dc2ade1645c9a0a0bd6a6ab7b8828bb66 Mon Sep 17 00:00:00 2001 From: "Wim R. Crols" Date: Mon, 4 Dec 2023 16:21:23 +0100 Subject: [PATCH 82/90] ALFREDAPI-536: Add static Swagger Doc --- docs/build-website.sh | 12 +- .../alfred-api/swagger-ui/favicon-16x16.png | Bin 0 -> 445 bytes .../alfred-api/swagger-ui/favicon-32x32.png | Bin 0 -> 1141 bytes docs/docs/alfred-api/swagger-ui/index.html | 111 ++++++++++++++++++ .../swagger-ui/oauth2-redirect.html | 60 ++++++++++ .../swagger-ui/swagger-ui-bundle.js | 99 ++++++++++++++++ .../swagger-ui/swagger-ui-bundle.js.map | 1 + .../swagger-ui-standalone-preset.js | 13 ++ .../swagger-ui-standalone-preset.js.map | 1 + .../docs/alfred-api/swagger-ui/swagger-ui.css | 2 + .../alfred-api/swagger-ui/swagger-ui.css.map | 1 + docs/docs/alfred-api/swagger-ui/swagger-ui.js | 8 ++ .../alfred-api/swagger-ui/swagger-ui.js.map | 1 + docs/docs/alfred-api/swagger-ui/swagger.json | 1 + docs/docs/alfred-api/user/user-guide.md | 2 +- 15 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 docs/docs/alfred-api/swagger-ui/favicon-16x16.png create mode 100644 docs/docs/alfred-api/swagger-ui/favicon-32x32.png create mode 100644 docs/docs/alfred-api/swagger-ui/index.html create mode 100644 docs/docs/alfred-api/swagger-ui/oauth2-redirect.html create mode 100644 docs/docs/alfred-api/swagger-ui/swagger-ui-bundle.js create mode 100644 docs/docs/alfred-api/swagger-ui/swagger-ui-bundle.js.map create mode 100644 docs/docs/alfred-api/swagger-ui/swagger-ui-standalone-preset.js create mode 100644 docs/docs/alfred-api/swagger-ui/swagger-ui-standalone-preset.js.map create mode 100644 docs/docs/alfred-api/swagger-ui/swagger-ui.css create mode 100644 docs/docs/alfred-api/swagger-ui/swagger-ui.css.map create mode 100644 docs/docs/alfred-api/swagger-ui/swagger-ui.js create mode 100644 docs/docs/alfred-api/swagger-ui/swagger-ui.js.map create mode 100644 docs/docs/alfred-api/swagger-ui/swagger.json diff --git a/docs/build-website.sh b/docs/build-website.sh index 2cb4c8d1..060cba3f 100755 --- a/docs/build-website.sh +++ b/docs/build-website.sh @@ -56,7 +56,6 @@ build_product_website() { sync } -# Both Alfred API Javadoc and Swagger doc are built by the git submodule of the 'alfred-api' repository build_alfredapi_javadoc() { echo "===== Generating javadoc =====" local productName="$1" @@ -72,10 +71,21 @@ build_alfredapi_javadoc() { cp -a "$alfredapidir/apix-interface/build/docs/javadoc" $outputdir } +build_alfredapi_swaggerdoc() { + echo "===== Copying swaggerdoc =====" + local productName="$1" + local swaggerdir="docs/$productName/swagger-ui" + local outputdir="build/website/$productName/" + + mkdir -p $outputdir + cp -a $swaggerdir $outputdir +} + rm -rf build/ build_and_split_manual alfred-api user "user-guide.md" build_product_website alfred-api build_alfredapi_javadoc alfred-api user +build_alfredapi_swaggerdoc alfred-api user find build/website -type f -name '*.html' -print0 | xargs -0 sed -i "/^<\!DOCTYPE html>$/a\ \<\!-- alfred-docs@$(git describe --always --dirty) --\>" diff --git a/docs/docs/alfred-api/swagger-ui/favicon-16x16.png b/docs/docs/alfred-api/swagger-ui/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..0f7e13b0d9903d27a9129950b1dad362361504e4 GIT binary patch literal 445 zcmV;u0Yd(XP)rNm2=6wQ7&2F}_`h_PI>(9Fx!5<0%l6W{u0OQ#*rglqx3__&vD?|#%fhn*Mn&YY1i+JQHqPvZ34FR@_E%P@x zzTL;Bw#nJXWY}D7^bC>-bx{t|^|R6Oci&MKvov8Op~S=}R=h^p-=vZ0uqG@LE6tP7 n92{cY$^db6>&z__iT?Z#Z8BG|DVcT0DjiaEd>Z!7_`J}8! zKk_$1lGm$vJOY&DjT-(&VGn0;R`iN9=1aOuG`H}BlY>&R3KbGER zB2$7euhH;y1C_LTQex%L6khZpkjFn!ajOUK)f3JLz+I;CE@(N)T)CM4AWjfl-(04= zrsMQ)#NG6nr^Y7!6LA;iHXh?UOFE%hhy>7dl=;I$J>g0BH_r|_4ctEsXx z2sDIQnwa*rcK=*3XUC$D{I@}DTNs@GCb7dB2%%nV%jR){xktt;Ah09op7x@l5D6B2 z0uBdt0YmcN!o?lMpu9Io(1&B1s{TUu*a>2&>Iycx__fbDRM8PYtLt+#G*xSt(cn}K zt!~W2{`9r)xkh^xodLS&FbYw`x$t&Vhl?)#f&k-lZIs<`$gTj{^#^HewuJz(WnUZZ z{Ty_aE;^93bhc-^^k6ZM!^e~$q5!Zz`XPta{a@651gPzaFx$&%IHL6hx$mSeAa#n6 zLkyc-M zs$qhBZhCNE^aIEV)H_~^IeqSRnvo!21Qc`Z;S9!IqXl4K(RUImejotzuG65LVuGS# zcqp@OA8~ln^4c^VihUew)IOX^E9KMtvSvnZ| zC@rl{f(B*PA26aFR`|X!!I(7x_|kq{rlqwhCia+CfNbOg_yYt0bDCc4g#h#`3jpCd zNAhr%4#Ye{i>ni$fzY%r0IS%l3HHZ4tTjOi=JW-t_iG~)oC!2C!52Cc|TAPaH zJ}l%m9yPmA-4#lJea@uf$a`(1;={rL2f*8;7%icbF}e^_`X#ndU=SI0nIn8hXPXHS zSN4rbF}jl0HWx(_`q`-SRa9jP8Ab!}sThNkQ634k=qXBVM4`o{M>qrLJD ze*%D)S;wpxG$d%FcDf-6%zMqWA+gw!C1~T5+|ys$G3Ksm&x59Lyd?0l+LWSk6hc4~ z+yC>|4f;X3#cq3!)>#Mvb-^co7LMrzqWeKB$21I>tJgaGFwu6eB%&j?@d*8GAx~In zI1p-lXVKtcvY7;$TX~wjYw|QhB%q!npQES%F~%Aqz~pJB%rNu!xAj;>xZt75!VHju zfFy%B-`3;Qf<{h94~I62zcHv}D5pS-QCN`M8K1>jN9mpbrFk=5no8j!00000NkvXX Hu0mjfOavUK literal 0 HcmV?d00001 diff --git a/docs/docs/alfred-api/swagger-ui/index.html b/docs/docs/alfred-api/swagger-ui/index.html new file mode 100644 index 00000000..96857852 --- /dev/null +++ b/docs/docs/alfred-api/swagger-ui/index.html @@ -0,0 +1,111 @@ + + + + + + + + Swagger UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + \ No newline at end of file diff --git a/docs/docs/alfred-api/swagger-ui/oauth2-redirect.html b/docs/docs/alfred-api/swagger-ui/oauth2-redirect.html new file mode 100644 index 00000000..eb00dc68 --- /dev/null +++ b/docs/docs/alfred-api/swagger-ui/oauth2-redirect.html @@ -0,0 +1,60 @@ + + + + + + diff --git a/docs/docs/alfred-api/swagger-ui/swagger-ui-bundle.js b/docs/docs/alfred-api/swagger-ui/swagger-ui-bundle.js new file mode 100644 index 00000000..385e8e51 --- /dev/null +++ b/docs/docs/alfred-api/swagger-ui/swagger-ui-bundle.js @@ -0,0 +1,99 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SwaggerUIBundle=t():e.SwaggerUIBundle=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="/dist",t(t.s=1220)}([function(e,t,n){"use strict";e.exports=n(93)},function(e,t,n){e.exports=n(1001)()},function(e,t,n){"use strict";t.__esModule=!0,t.default=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},function(e,t,n){"use strict";t.__esModule=!0;var r=n(331),i=function(e){return e&&e.__esModule?e:{default:e}}(r);t.default=function(){function e(e,t){for(var n=0;n>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?d(e)+t:t}function v(){return!0}function g(e,t,n){return(0===e||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function y(e,t){return b(e,t,0)}function _(e,t){return b(e,t,t)}function b(e,t,n){return void 0===e?n:e<0?Math.max(0,t+e):void 0===t?e:Math.min(t,e)}function x(e){this.next=e}function w(e,t,n,r){var i=0===e?t:1===e?n:[t,n];return r?r.value=i:r={value:i,done:!1},r}function k(){return{value:void 0,done:!0}}function E(e){return!!A(e)}function S(e){return e&&"function"==typeof e.next}function C(e){var t=A(e);return t&&t.call(e)}function A(e){var t=e&&(wn&&e[wn]||e[kn]);if("function"==typeof t)return t}function D(e){return e&&"number"==typeof e.length}function O(e){return null===e||void 0===e?B():o(e)?e.toSeq():z(e)}function M(e){return null===e||void 0===e?B().toKeyedSeq():o(e)?a(e)?e.toSeq():e.fromEntrySeq():L(e)}function T(e){return null===e||void 0===e?B():o(e)?a(e)?e.entrySeq():e.toIndexedSeq():q(e)}function P(e){return(null===e||void 0===e?B():o(e)?a(e)?e.entrySeq():e:q(e)).toSetSeq()}function I(e){this._array=e,this.size=e.length}function R(e){var t=Object.keys(e);this._object=e,this._keys=t,this.size=t.length}function j(e){this._iterable=e,this.size=e.length||e.size}function F(e){this._iterator=e,this._iteratorCache=[]}function N(e){return!(!e||!e[Sn])}function B(){return Cn||(Cn=new I([]))}function L(e){var t=Array.isArray(e)?new I(e).fromEntrySeq():S(e)?new F(e).fromEntrySeq():E(e)?new j(e).fromEntrySeq():"object"==typeof e?new R(e):void 0;if(!t)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+e);return t}function q(e){var t=U(e);if(!t)throw new TypeError("Expected Array or iterable object of values: "+e);return t}function z(e){var t=U(e)||"object"==typeof e&&new R(e);if(!t)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+e);return t}function U(e){return D(e)?new I(e):S(e)?new F(e):E(e)?new j(e):void 0}function W(e,t,n,r){var i=e._cache;if(i){for(var o=i.length-1,a=0;a<=o;a++){var s=i[n?o-a:a];if(!1===t(s[1],r?s[0]:a,e))return a+1}return a}return e.__iterateUncached(t,n)}function V(e,t,n,r){var i=e._cache;if(i){var o=i.length-1,a=0;return new x(function(){var e=i[n?o-a:a];return a++>o?k():w(t,r?e[0]:a-1,e[1])})}return e.__iteratorUncached(t,n)}function H(e,t){return t?G(t,e,"",{"":e}):J(e)}function G(e,t,n,r){return Array.isArray(t)?e.call(r,n,T(t).map(function(n,r){return G(e,n,r,t)})):K(t)?e.call(r,n,M(t).map(function(n,r){return G(e,n,r,t)})):t}function J(e){return Array.isArray(e)?T(e).map(J).toList():K(e)?M(e).map(J).toMap():e}function K(e){return e&&(e.constructor===Object||void 0===e.constructor)}function X(e,t){if(e===t||e!==e&&t!==t)return!0;if(!e||!t)return!1;if("function"==typeof e.valueOf&&"function"==typeof t.valueOf){if(e=e.valueOf(),t=t.valueOf(),e===t||e!==e&&t!==t)return!0;if(!e||!t)return!1}return!("function"!=typeof e.equals||"function"!=typeof t.equals||!e.equals(t))}function Y(e,t){if(e===t)return!0;if(!o(t)||void 0!==e.size&&void 0!==t.size&&e.size!==t.size||void 0!==e.__hash&&void 0!==t.__hash&&e.__hash!==t.__hash||a(e)!==a(t)||s(e)!==s(t)||l(e)!==l(t))return!1;if(0===e.size&&0===t.size)return!0;var n=!u(e);if(l(e)){var r=e.entries();return t.every(function(e,t){var i=r.next().value;return i&&X(i[1],e)&&(n||X(i[0],t))})&&r.next().done}var i=!1;if(void 0===e.size)if(void 0===t.size)"function"==typeof e.cacheResult&&e.cacheResult();else{i=!0;var c=e;e=t,t=c}var p=!0,f=t.__iterate(function(t,r){if(n?!e.has(t):i?!X(t,e.get(r,vn)):!X(e.get(r,vn),t))return p=!1,!1});return p&&e.size===f}function $(e,t){if(!(this instanceof $))return new $(e,t);if(this._value=e,this.size=void 0===t?1/0:Math.max(0,t),0===this.size){if(An)return An;An=this}}function Z(e,t){if(!e)throw new Error(t)}function Q(e,t,n){if(!(this instanceof Q))return new Q(e,t,n);if(Z(0!==n,"Cannot step a Range by 0"),e=e||0,void 0===t&&(t=1/0),n=void 0===n?1:Math.abs(n),t>>1&1073741824|3221225471&e}function oe(e){if(!1===e||null===e||void 0===e)return 0;if("function"==typeof e.valueOf&&(!1===(e=e.valueOf())||null===e||void 0===e))return 0;if(!0===e)return 1;var t=typeof e;if("number"===t){if(e!==e||e===1/0)return 0;var n=0|e;for(n!==e&&(n^=4294967295*e);e>4294967295;)e/=4294967295,n^=e;return ie(n)}if("string"===t)return e.length>Fn?ae(e):se(e);if("function"==typeof e.hashCode)return e.hashCode();if("object"===t)return ue(e);if("function"==typeof e.toString)return se(e.toString());throw new Error("Value type "+t+" cannot be hashed.")}function ae(e){var t=Ln[e];return void 0===t&&(t=se(e),Bn===Nn&&(Bn=0,Ln={}),Bn++,Ln[e]=t),t}function se(e){for(var t=0,n=0;n0)switch(e.nodeType){case 1:return e.uniqueID;case 9:return e.documentElement&&e.documentElement.uniqueID}}function ce(e){Z(e!==1/0,"Cannot perform this action with an infinite size.")}function pe(e){return null===e||void 0===e?we():fe(e)&&!l(e)?e:we().withMutations(function(t){var r=n(e);ce(r.size),r.forEach(function(e,n){return t.set(n,e)})})}function fe(e){return!(!e||!e[qn])}function he(e,t){this.ownerID=e,this.entries=t}function de(e,t,n){this.ownerID=e,this.bitmap=t,this.nodes=n}function me(e,t,n){this.ownerID=e,this.count=t,this.nodes=n}function ve(e,t,n){this.ownerID=e,this.keyHash=t,this.entries=n}function ge(e,t,n){this.ownerID=e,this.keyHash=t,this.entry=n}function ye(e,t,n){this._type=t,this._reverse=n,this._stack=e._root&&be(e._root)}function _e(e,t){return w(e,t[0],t[1])}function be(e,t){return{node:e,index:0,__prev:t}}function xe(e,t,n,r){var i=Object.create(zn);return i.size=e,i._root=t,i.__ownerID=n,i.__hash=r,i.__altered=!1,i}function we(){return Un||(Un=xe(0))}function ke(e,t,n){var r,i;if(e._root){var o=c(gn),a=c(yn);if(r=Ee(e._root,e.__ownerID,0,void 0,t,n,o,a),!a.value)return e;i=e.size+(o.value?n===vn?-1:1:0)}else{if(n===vn)return e;i=1,r=new he(e.__ownerID,[[t,n]])}return e.__ownerID?(e.size=i,e._root=r,e.__hash=void 0,e.__altered=!0,e):r?xe(i,r):we()}function Ee(e,t,n,r,i,o,a,s){return e?e.update(t,n,r,i,o,a,s):o===vn?e:(p(s),p(a),new ge(t,r,[i,o]))}function Se(e){return e.constructor===ge||e.constructor===ve}function Ce(e,t,n,r,i){if(e.keyHash===r)return new ve(t,r,[e.entry,i]);var o,a=(0===n?e.keyHash:e.keyHash>>>n)&mn,s=(0===n?r:r>>>n)&mn;return new de(t,1<>>=1)a[s]=1&n?t[o++]:void 0;return a[r]=i,new me(e,o+1,a)}function Me(e,t,r){for(var i=[],a=0;a>1&1431655765,e=(858993459&e)+(e>>2&858993459),e=e+(e>>4)&252645135,e+=e>>8,127&(e+=e>>16)}function Fe(e,t,n,r){var i=r?e:h(e);return i[t]=n,i}function Ne(e,t,n,r){var i=e.length+1;if(r&&t+1===i)return e[t]=n,e;for(var o=new Array(i),a=0,s=0;s0&&io?0:o-n,l=a-n;return l>dn&&(l=dn),function(){if(i===l)return Xn;var e=t?--l:i++;return r&&r[e]}}function i(e,r,i){var s,u=e&&e.array,l=i>o?0:o-i>>r,c=1+(a-i>>r);return c>dn&&(c=dn),function(){for(;;){if(s){var e=s();if(e!==Xn)return e;s=null}if(l===c)return Xn;var o=t?--c:l++;s=n(u&&u[o],r-hn,i+(o<=e.size||t<0)return e.withMutations(function(e){t<0?Xe(e,t).set(0,n):Xe(e,0,t+1).set(t,n)});t+=e._origin;var r=e._tail,i=e._root,o=c(yn);return t>=$e(e._capacity)?r=Ge(r,e.__ownerID,0,t,n,o):i=Ge(i,e.__ownerID,e._level,t,n,o),o.value?e.__ownerID?(e._root=i,e._tail=r,e.__hash=void 0,e.__altered=!0,e):We(e._origin,e._capacity,e._level,i,r):e}function Ge(e,t,n,r,i,o){var a=r>>>n&mn,s=e&&a0){var l=e&&e.array[a],c=Ge(l,t,n-hn,r,i,o);return c===l?e:(u=Je(e,t),u.array[a]=c,u)}return s&&e.array[a]===i?e:(p(o),u=Je(e,t),void 0===i&&a===u.array.length-1?u.array.pop():u.array[a]=i,u)}function Je(e,t){return t&&e&&t===e.ownerID?e:new ze(e?e.array.slice():[],t)}function Ke(e,t){if(t>=$e(e._capacity))return e._tail;if(t<1<0;)n=n.array[t>>>r&mn],r-=hn;return n}}function Xe(e,t,n){void 0!==t&&(t|=0),void 0!==n&&(n|=0);var r=e.__ownerID||new f,i=e._origin,o=e._capacity,a=i+t,s=void 0===n?o:n<0?o+n:i+n;if(a===i&&s===o)return e;if(a>=s)return e.clear();for(var u=e._level,l=e._root,c=0;a+c<0;)l=new ze(l&&l.array.length?[void 0,l]:[],r),u+=hn,c+=1<=1<p?new ze([],r):d;if(d&&h>p&&ahn;g-=hn){var y=p>>>g&mn;v=v.array[y]=Je(v.array[y],r)}v.array[p>>>hn&mn]=d}if(s=h)a-=h,s-=h,u=hn,l=null,m=m&&m.removeBefore(r,0,a);else if(a>i||h>>u&mn;if(_!==h>>>u&mn)break;_&&(c+=(1<i&&(l=l.removeBefore(r,u,a-c)),l&&ha&&(a=l.size),o(u)||(l=l.map(function(e){return H(e)})),i.push(l)}return a>e.size&&(e=e.setSize(a)),Ie(e,t,i)}function $e(e){return e>>hn<=dn&&a.size>=2*o.size?(i=a.filter(function(e,t){return void 0!==e&&s!==t}),r=i.toKeyedSeq().map(function(e){return e[0]}).flip().toMap(),e.__ownerID&&(r.__ownerID=i.__ownerID=e.__ownerID)):(r=o.remove(t),i=s===a.size-1?a.pop():a.set(s,void 0))}else if(u){if(n===a.get(s)[1])return e;r=o,i=a.set(s,[t,n])}else r=o.set(t,a.size),i=a.set(a.size,[t,n]);return e.__ownerID?(e.size=r.size,e._map=r,e._list=i,e.__hash=void 0,e):et(r,i)}function rt(e,t){this._iter=e,this._useKeys=t,this.size=e.size}function it(e){this._iter=e,this.size=e.size}function ot(e){this._iter=e,this.size=e.size}function at(e){this._iter=e,this.size=e.size}function st(e){var t=Dt(e);return t._iter=e,t.size=e.size,t.flip=function(){return e},t.reverse=function(){var t=e.reverse.apply(this);return t.flip=function(){return e.reverse()},t},t.has=function(t){return e.includes(t)},t.includes=function(t){return e.has(t)},t.cacheResult=Ot,t.__iterateUncached=function(t,n){var r=this;return e.__iterate(function(e,n){return!1!==t(n,e,r)},n)},t.__iteratorUncached=function(t,n){if(t===xn){var r=e.__iterator(t,n);return new x(function(){var e=r.next();if(!e.done){var t=e.value[0];e.value[0]=e.value[1],e.value[1]=t}return e})}return e.__iterator(t===bn?_n:bn,n)},t}function ut(e,t,n){var r=Dt(e);return r.size=e.size,r.has=function(t){return e.has(t)},r.get=function(r,i){var o=e.get(r,vn);return o===vn?i:t.call(n,o,r,e)},r.__iterateUncached=function(r,i){var o=this;return e.__iterate(function(e,i,a){return!1!==r(t.call(n,e,i,a),i,o)},i)},r.__iteratorUncached=function(r,i){var o=e.__iterator(xn,i);return new x(function(){var i=o.next();if(i.done)return i;var a=i.value,s=a[0];return w(r,s,t.call(n,a[1],s,e),i)})},r}function lt(e,t){var n=Dt(e);return n._iter=e,n.size=e.size,n.reverse=function(){return e},e.flip&&(n.flip=function(){var t=st(e);return t.reverse=function(){return e.flip()},t}),n.get=function(n,r){return e.get(t?n:-1-n,r)},n.has=function(n){return e.has(t?n:-1-n)},n.includes=function(t){return e.includes(t)},n.cacheResult=Ot,n.__iterate=function(t,n){var r=this;return e.__iterate(function(e,n){return t(e,n,r)},!n)},n.__iterator=function(t,n){return e.__iterator(t,!n)},n}function ct(e,t,n,r){var i=Dt(e);return r&&(i.has=function(r){var i=e.get(r,vn);return i!==vn&&!!t.call(n,i,r,e)},i.get=function(r,i){var o=e.get(r,vn);return o!==vn&&t.call(n,o,r,e)?o:i}),i.__iterateUncached=function(i,o){var a=this,s=0;return e.__iterate(function(e,o,u){if(t.call(n,e,o,u))return s++,i(e,r?o:s-1,a)},o),s},i.__iteratorUncached=function(i,o){var a=e.__iterator(xn,o),s=0;return new x(function(){for(;;){var o=a.next();if(o.done)return o;var u=o.value,l=u[0],c=u[1];if(t.call(n,c,l,e))return w(i,r?l:s++,c,o)}})},i}function pt(e,t,n){var r=pe().asMutable();return e.__iterate(function(i,o){r.update(t.call(n,i,o,e),0,function(e){return e+1})}),r.asImmutable()}function ft(e,t,n){var r=a(e),i=(l(e)?Ze():pe()).asMutable();e.__iterate(function(o,a){i.update(t.call(n,o,a,e),function(e){return e=e||[],e.push(r?[a,o]:o),e})});var o=At(e);return i.map(function(t){return Et(e,o(t))})}function ht(e,t,n,r){var i=e.size;if(void 0!==t&&(t|=0),void 0!==n&&(n===1/0?n=i:n|=0),g(t,n,i))return e;var o=y(t,i),a=_(n,i);if(o!==o||a!==a)return ht(e.toSeq().cacheResult(),t,n,r);var s,u=a-o;u===u&&(s=u<0?0:u);var l=Dt(e);return l.size=0===s?s:e.size&&s||void 0,!r&&N(e)&&s>=0&&(l.get=function(t,n){return t=m(this,t),t>=0&&ts)return k();var e=i.next();return r||t===bn?e:t===_n?w(t,u-1,void 0,e):w(t,u-1,e.value[1],e)})},l}function dt(e,t,n){var r=Dt(e);return r.__iterateUncached=function(r,i){var o=this;if(i)return this.cacheResult().__iterate(r,i);var a=0;return e.__iterate(function(e,i,s){return t.call(n,e,i,s)&&++a&&r(e,i,o)}),a},r.__iteratorUncached=function(r,i){var o=this;if(i)return this.cacheResult().__iterator(r,i);var a=e.__iterator(xn,i),s=!0;return new x(function(){if(!s)return k();var e=a.next();if(e.done)return e;var i=e.value,u=i[0],l=i[1];return t.call(n,l,u,o)?r===xn?e:w(r,u,l,e):(s=!1,k())})},r}function mt(e,t,n,r){var i=Dt(e);return i.__iterateUncached=function(i,o){var a=this;if(o)return this.cacheResult().__iterate(i,o);var s=!0,u=0;return e.__iterate(function(e,o,l){if(!s||!(s=t.call(n,e,o,l)))return u++,i(e,r?o:u-1,a)}),u},i.__iteratorUncached=function(i,o){var a=this;if(o)return this.cacheResult().__iterator(i,o);var s=e.__iterator(xn,o),u=!0,l=0;return new x(function(){var e,o,c;do{if(e=s.next(),e.done)return r||i===bn?e:i===_n?w(i,l++,void 0,e):w(i,l++,e.value[1],e);var p=e.value;o=p[0],c=p[1],u&&(u=t.call(n,c,o,a))}while(u);return i===xn?e:w(i,o,c,e)})},i}function vt(e,t){var r=a(e),i=[e].concat(t).map(function(e){return o(e)?r&&(e=n(e)):e=r?L(e):q(Array.isArray(e)?e:[e]),e}).filter(function(e){return 0!==e.size});if(0===i.length)return e;if(1===i.length){var u=i[0];if(u===e||r&&a(u)||s(e)&&s(u))return u}var l=new I(i);return r?l=l.toKeyedSeq():s(e)||(l=l.toSetSeq()),l=l.flatten(!0),l.size=i.reduce(function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}},0),l}function gt(e,t,n){var r=Dt(e);return r.__iterateUncached=function(r,i){function a(e,l){var c=this;e.__iterate(function(e,i){return(!t||l0}function kt(e,n,r){var i=Dt(e);return i.size=new I(r).map(function(e){return e.size}).min(),i.__iterate=function(e,t){for(var n,r=this.__iterator(bn,t),i=0;!(n=r.next()).done&&!1!==e(n.value,i++,this););return i},i.__iteratorUncached=function(e,i){var o=r.map(function(e){return e=t(e),C(i?e.reverse():e)}),a=0,s=!1;return new x(function(){var t;return s||(t=o.map(function(e){return e.next()}),s=t.some(function(e){return e.done})),s?k():w(e,a++,n.apply(null,t.map(function(e){return e.value})))})},i}function Et(e,t){return N(e)?t:e.constructor(t)}function St(e){if(e!==Object(e))throw new TypeError("Expected [K, V] tuple: "+e)}function Ct(e){return ce(e.size),d(e)}function At(e){return a(e)?n:s(e)?r:i}function Dt(e){return Object.create((a(e)?M:s(e)?T:P).prototype)}function Ot(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):O.prototype.cacheResult.call(this)}function Mt(e,t){return e>t?1:et?-1:0}function on(e){if(e.size===1/0)return 0;var t=l(e),n=a(e),r=t?1:0;return an(e.__iterate(n?t?function(e,t){r=31*r+sn(oe(e),oe(t))|0}:function(e,t){r=r+sn(oe(e),oe(t))|0}:t?function(e){r=31*r+oe(e)|0}:function(e){r=r+oe(e)|0}),r)}function an(e,t){return t=Mn(t,3432918353),t=Mn(t<<15|t>>>-15,461845907),t=Mn(t<<13|t>>>-13,5),t=(t+3864292196|0)^e,t=Mn(t^t>>>16,2246822507),t=Mn(t^t>>>13,3266489909),t=ie(t^t>>>16)}function sn(e,t){return e^t+2654435769+(e<<6)+(e>>2)|0}var un=Array.prototype.slice;e(n,t),e(r,t),e(i,t),t.isIterable=o,t.isKeyed=a,t.isIndexed=s,t.isAssociative=u,t.isOrdered=l,t.Keyed=n,t.Indexed=r,t.Set=i;var ln="@@__IMMUTABLE_ITERABLE__@@",cn="@@__IMMUTABLE_KEYED__@@",pn="@@__IMMUTABLE_INDEXED__@@",fn="@@__IMMUTABLE_ORDERED__@@",hn=5,dn=1<r?k():w(e,i,n[t?r-i++:i++])})},e(R,M),R.prototype.get=function(e,t){return void 0===t||this.has(e)?this._object[e]:t},R.prototype.has=function(e){return this._object.hasOwnProperty(e)},R.prototype.__iterate=function(e,t){for(var n=this._object,r=this._keys,i=r.length-1,o=0;o<=i;o++){var a=r[t?i-o:o];if(!1===e(n[a],a,this))return o+1}return o},R.prototype.__iterator=function(e,t){var n=this._object,r=this._keys,i=r.length-1,o=0;return new x(function(){var a=r[t?i-o:o];return o++>i?k():w(e,a,n[a])})},R.prototype[fn]=!0,e(j,T),j.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);var n=this._iterable,r=C(n),i=0;if(S(r))for(var o;!(o=r.next()).done&&!1!==e(o.value,i++,this););return i},j.prototype.__iteratorUncached=function(e,t){if(t)return this.cacheResult().__iterator(e,t);var n=this._iterable,r=C(n);if(!S(r))return new x(k);var i=0;return new x(function(){var t=r.next();return t.done?t:w(e,i++,t.value)})},e(F,T),F.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);for(var n=this._iterator,r=this._iteratorCache,i=0;i=r.length){var t=n.next();if(t.done)return t;r[i]=t.value}return w(e,i,r[i++])})};var Cn;e($,T),$.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},$.prototype.get=function(e,t){return this.has(e)?this._value:t},$.prototype.includes=function(e){return X(this._value,e)},$.prototype.slice=function(e,t){var n=this.size;return g(e,t,n)?this:new $(this._value,_(t,n)-y(e,n))},$.prototype.reverse=function(){return this},$.prototype.indexOf=function(e){return X(this._value,e)?0:-1},$.prototype.lastIndexOf=function(e){return X(this._value,e)?this.size:-1},$.prototype.__iterate=function(e,t){for(var n=0;n=0&&t=0&&nn?k():w(e,o++,a)})},Q.prototype.equals=function(e){return e instanceof Q?this._start===e._start&&this._end===e._end&&this._step===e._step:Y(this,e)};var Dn;e(ee,t),e(te,ee),e(ne,ee),e(re,ee),ee.Keyed=te,ee.Indexed=ne,ee.Set=re;var On,Mn="function"==typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function(e,t){e|=0,t|=0;var n=65535&e,r=65535&t;return n*r+((e>>>16)*r+n*(t>>>16)<<16>>>0)|0},Tn=Object.isExtensible,Pn=function(){try{return Object.defineProperty({},"@",{}),!0}catch(e){return!1}}(),In="function"==typeof WeakMap;In&&(On=new WeakMap);var Rn=0,jn="__immutablehash__";"function"==typeof Symbol&&(jn=Symbol(jn));var Fn=16,Nn=255,Bn=0,Ln={};e(pe,te),pe.of=function(){var e=un.call(arguments,0);return we().withMutations(function(t){for(var n=0;n=e.length)throw new Error("Missing value for key: "+e[n]);t.set(e[n],e[n+1])}})},pe.prototype.toString=function(){return this.__toString("Map {","}")},pe.prototype.get=function(e,t){return this._root?this._root.get(0,void 0,e,t):t},pe.prototype.set=function(e,t){return ke(this,e,t)},pe.prototype.setIn=function(e,t){return this.updateIn(e,vn,function(){return t})},pe.prototype.remove=function(e){return ke(this,e,vn)},pe.prototype.deleteIn=function(e){return this.updateIn(e,function(){return vn})},pe.prototype.update=function(e,t,n){return 1===arguments.length?e(this):this.updateIn([e],t,n)},pe.prototype.updateIn=function(e,t,n){n||(n=t,t=void 0);var r=Re(this,Tt(e),t,n);return r===vn?void 0:r},pe.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):we()},pe.prototype.merge=function(){return Me(this,void 0,arguments)},pe.prototype.mergeWith=function(e){return Me(this,e,un.call(arguments,1))},pe.prototype.mergeIn=function(e){var t=un.call(arguments,1);return this.updateIn(e,we(),function(e){return"function"==typeof e.merge?e.merge.apply(e,t):t[t.length-1]})},pe.prototype.mergeDeep=function(){return Me(this,Te,arguments)},pe.prototype.mergeDeepWith=function(e){var t=un.call(arguments,1);return Me(this,Pe(e),t)},pe.prototype.mergeDeepIn=function(e){var t=un.call(arguments,1);return this.updateIn(e,we(),function(e){return"function"==typeof e.mergeDeep?e.mergeDeep.apply(e,t):t[t.length-1]})},pe.prototype.sort=function(e){return Ze(bt(this,e))},pe.prototype.sortBy=function(e,t){return Ze(bt(this,t,e))},pe.prototype.withMutations=function(e){var t=this.asMutable();return e(t),t.wasAltered()?t.__ensureOwner(this.__ownerID):this},pe.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new f)},pe.prototype.asImmutable=function(){return this.__ensureOwner()},pe.prototype.wasAltered=function(){return this.__altered},pe.prototype.__iterator=function(e,t){return new ye(this,e,t)},pe.prototype.__iterate=function(e,t){var n=this,r=0;return this._root&&this._root.iterate(function(t){return r++,e(t[1],t[0],n)},t),r},pe.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?xe(this.size,this._root,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},pe.isMap=fe;var qn="@@__IMMUTABLE_MAP__@@",zn=pe.prototype;zn[qn]=!0,zn.delete=zn.remove,zn.removeIn=zn.deleteIn,he.prototype.get=function(e,t,n,r){for(var i=this.entries,o=0,a=i.length;o=Wn)return Ae(e,u,r,i);var d=e&&e===this.ownerID,m=d?u:h(u);return f?s?l===c-1?m.pop():m[l]=m.pop():m[l]=[r,i]:m.push([r,i]),d?(this.entries=m,this):new he(e,m)}},de.prototype.get=function(e,t,n,r){void 0===t&&(t=oe(n));var i=1<<((0===e?t:t>>>e)&mn),o=this.bitmap;return 0==(o&i)?r:this.nodes[je(o&i-1)].get(e+hn,t,n,r)},de.prototype.update=function(e,t,n,r,i,o,a){void 0===n&&(n=oe(r));var s=(0===t?n:n>>>t)&mn,u=1<=Vn)return Oe(e,f,l,s,d);if(c&&!d&&2===f.length&&Se(f[1^p]))return f[1^p];if(c&&d&&1===f.length&&Se(d))return d;var m=e&&e===this.ownerID,v=c?d?l:l^u:l|u,g=c?d?Fe(f,p,d,m):Be(f,p,m):Ne(f,p,d,m);return m?(this.bitmap=v,this.nodes=g,this):new de(e,v,g)},me.prototype.get=function(e,t,n,r){void 0===t&&(t=oe(n));var i=(0===e?t:t>>>e)&mn,o=this.nodes[i];return o?o.get(e+hn,t,n,r):r},me.prototype.update=function(e,t,n,r,i,o,a){void 0===n&&(n=oe(r));var s=(0===t?n:n>>>t)&mn,u=i===vn,l=this.nodes,c=l[s];if(u&&!c)return this;var p=Ee(c,e,t+hn,n,r,i,o,a);if(p===c)return this;var f=this.count;if(c){if(!p&&--f=0&&e>>t&mn;if(r>=this.array.length)return new ze([],e);var i,o=0===r;if(t>0){var a=this.array[r];if((i=a&&a.removeBefore(e,t-hn,n))===a&&o)return this}if(o&&!i)return this;var s=Je(this,e);if(!o)for(var u=0;u>>t&mn;if(r>=this.array.length)return this;var i;if(t>0){var o=this.array[r];if((i=o&&o.removeAfter(e,t-hn,n))===o&&r===this.array.length-1)return this}var a=Je(this,e);return a.array.splice(r+1),i&&(a.array[r]=i),a};var Kn,Xn={};e(Ze,pe),Ze.of=function(){return this(arguments)},Ze.prototype.toString=function(){return this.__toString("OrderedMap {","}")},Ze.prototype.get=function(e,t){var n=this._map.get(e);return void 0!==n?this._list.get(n)[1]:t},Ze.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._map.clear(),this._list.clear(),this):tt()},Ze.prototype.set=function(e,t){return nt(this,e,t)},Ze.prototype.remove=function(e){return nt(this,e,vn)},Ze.prototype.wasAltered=function(){return this._map.wasAltered()||this._list.wasAltered()},Ze.prototype.__iterate=function(e,t){var n=this;return this._list.__iterate(function(t){return t&&e(t[1],t[0],n)},t)},Ze.prototype.__iterator=function(e,t){return this._list.fromEntrySeq().__iterator(e,t)},Ze.prototype.__ensureOwner=function(e){if(e===this.__ownerID)return this;var t=this._map.__ensureOwner(e),n=this._list.__ensureOwner(e);return e?et(t,n,e,this.__hash):(this.__ownerID=e,this._map=t,this._list=n,this)},Ze.isOrderedMap=Qe,Ze.prototype[fn]=!0,Ze.prototype.delete=Ze.prototype.remove;var Yn;e(rt,M),rt.prototype.get=function(e,t){return this._iter.get(e,t)},rt.prototype.has=function(e){return this._iter.has(e)},rt.prototype.valueSeq=function(){return this._iter.valueSeq()},rt.prototype.reverse=function(){var e=this,t=lt(this,!0);return this._useKeys||(t.valueSeq=function(){return e._iter.toSeq().reverse()}),t},rt.prototype.map=function(e,t){var n=this,r=ut(this,e,t);return this._useKeys||(r.valueSeq=function(){return n._iter.toSeq().map(e,t)}),r},rt.prototype.__iterate=function(e,t){var n,r=this;return this._iter.__iterate(this._useKeys?function(t,n){return e(t,n,r)}:(n=t?Ct(this):0,function(i){return e(i,t?--n:n++,r)}),t)},rt.prototype.__iterator=function(e,t){if(this._useKeys)return this._iter.__iterator(e,t);var n=this._iter.__iterator(bn,t),r=t?Ct(this):0;return new x(function(){var i=n.next();return i.done?i:w(e,t?--r:r++,i.value,i)})},rt.prototype[fn]=!0,e(it,T),it.prototype.includes=function(e){return this._iter.includes(e)},it.prototype.__iterate=function(e,t){var n=this,r=0;return this._iter.__iterate(function(t){return e(t,r++,n)},t)},it.prototype.__iterator=function(e,t){var n=this._iter.__iterator(bn,t),r=0;return new x(function(){var t=n.next();return t.done?t:w(e,r++,t.value,t)})},e(ot,P),ot.prototype.has=function(e){return this._iter.includes(e)},ot.prototype.__iterate=function(e,t){var n=this;return this._iter.__iterate(function(t){return e(t,t,n)},t)},ot.prototype.__iterator=function(e,t){var n=this._iter.__iterator(bn,t);return new x(function(){var t=n.next();return t.done?t:w(e,t.value,t.value,t)})},e(at,M),at.prototype.entrySeq=function(){return this._iter.toSeq()},at.prototype.__iterate=function(e,t){var n=this;return this._iter.__iterate(function(t){if(t){St(t);var r=o(t);return e(r?t.get(1):t[1],r?t.get(0):t[0],n)}},t)},at.prototype.__iterator=function(e,t){var n=this._iter.__iterator(bn,t);return new x(function(){for(;;){var t=n.next();if(t.done)return t;var r=t.value;if(r){St(r);var i=o(r);return w(e,i?r.get(0):r[0],i?r.get(1):r[1],t)}}})},it.prototype.cacheResult=rt.prototype.cacheResult=ot.prototype.cacheResult=at.prototype.cacheResult=Ot,e(Pt,te),Pt.prototype.toString=function(){return this.__toString(Rt(this)+" {","}")},Pt.prototype.has=function(e){return this._defaultValues.hasOwnProperty(e)},Pt.prototype.get=function(e,t){if(!this.has(e))return t;var n=this._defaultValues[e];return this._map?this._map.get(e,n):n},Pt.prototype.clear=function(){if(this.__ownerID)return this._map&&this._map.clear(),this;var e=this.constructor;return e._empty||(e._empty=It(this,we()))},Pt.prototype.set=function(e,t){if(!this.has(e))throw new Error('Cannot set unknown key "'+e+'" on '+Rt(this));if(this._map&&!this._map.has(e)){if(t===this._defaultValues[e])return this}var n=this._map&&this._map.set(e,t);return this.__ownerID||n===this._map?this:It(this,n)},Pt.prototype.remove=function(e){if(!this.has(e))return this;var t=this._map&&this._map.remove(e);return this.__ownerID||t===this._map?this:It(this,t)},Pt.prototype.wasAltered=function(){return this._map.wasAltered()},Pt.prototype.__iterator=function(e,t){var r=this;return n(this._defaultValues).map(function(e,t){return r.get(t)}).__iterator(e,t)},Pt.prototype.__iterate=function(e,t){var r=this;return n(this._defaultValues).map(function(e,t){return r.get(t)}).__iterate(e,t)},Pt.prototype.__ensureOwner=function(e){if(e===this.__ownerID)return this;var t=this._map&&this._map.__ensureOwner(e);return e?It(this,t,e):(this.__ownerID=e,this._map=t,this)};var $n=Pt.prototype;$n.delete=$n.remove,$n.deleteIn=$n.removeIn=zn.removeIn,$n.merge=zn.merge,$n.mergeWith=zn.mergeWith,$n.mergeIn=zn.mergeIn,$n.mergeDeep=zn.mergeDeep,$n.mergeDeepWith=zn.mergeDeepWith,$n.mergeDeepIn=zn.mergeDeepIn,$n.setIn=zn.setIn,$n.update=zn.update,$n.updateIn=zn.updateIn,$n.withMutations=zn.withMutations,$n.asMutable=zn.asMutable,$n.asImmutable=zn.asImmutable,e(Nt,re),Nt.of=function(){return this(arguments)},Nt.fromKeys=function(e){return this(n(e).keySeq())},Nt.prototype.toString=function(){return this.__toString("Set {","}")},Nt.prototype.has=function(e){return this._map.has(e)},Nt.prototype.add=function(e){return Lt(this,this._map.set(e,!0))},Nt.prototype.remove=function(e){return Lt(this,this._map.remove(e))},Nt.prototype.clear=function(){return Lt(this,this._map.clear())},Nt.prototype.union=function(){var e=un.call(arguments,0);return e=e.filter(function(e){return 0!==e.size}),0===e.length?this:0!==this.size||this.__ownerID||1!==e.length?this.withMutations(function(t){for(var n=0;n=0;n--)t={value:arguments[n],next:t};return this.__ownerID?(this.size=e,this._head=t,this.__hash=void 0,this.__altered=!0,this):Kt(e,t)},Gt.prototype.pushAll=function(e){if(e=r(e),0===e.size)return this;ce(e.size);var t=this.size,n=this._head;return e.reverse().forEach(function(e){t++,n={value:e,next:n}}),this.__ownerID?(this.size=t,this._head=n,this.__hash=void 0,this.__altered=!0,this):Kt(t,n)},Gt.prototype.pop=function(){return this.slice(1)},Gt.prototype.unshift=function(){return this.push.apply(this,arguments)},Gt.prototype.unshiftAll=function(e){return this.pushAll(e)},Gt.prototype.shift=function(){return this.pop.apply(this,arguments)},Gt.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):Xt()},Gt.prototype.slice=function(e,t){if(g(e,t,this.size))return this;var n=y(e,this.size);if(_(t,this.size)!==this.size)return ne.prototype.slice.call(this,e,t);for(var r=this.size-n,i=this._head;n--;)i=i.next;return this.__ownerID?(this.size=r,this._head=i,this.__hash=void 0,this.__altered=!0,this):Kt(r,i)},Gt.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?Kt(this.size,this._head,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},Gt.prototype.__iterate=function(e,t){if(t)return this.reverse().__iterate(e);for(var n=0,r=this._head;r&&!1!==e(r.value,n++,this);)r=r.next;return n},Gt.prototype.__iterator=function(e,t){if(t)return this.reverse().__iterator(e);var n=0,r=this._head;return new x(function(){if(r){var t=r.value;return r=r.next,w(e,n++,t)}return k()})},Gt.isStack=Jt;var rr="@@__IMMUTABLE_STACK__@@",ir=Gt.prototype;ir[rr]=!0,ir.withMutations=zn.withMutations,ir.asMutable=zn.asMutable,ir.asImmutable=zn.asImmutable,ir.wasAltered=zn.wasAltered;var or;t.Iterator=x,Yt(t,{toArray:function(){ce(this.size);var e=new Array(this.size||0);return this.valueSeq().__iterate(function(t,n){e[n]=t}),e},toIndexedSeq:function(){return new it(this)},toJS:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJS?e.toJS():e}).__toJS()},toJSON:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJSON?e.toJSON():e}).__toJS()},toKeyedSeq:function(){return new rt(this,!0)},toMap:function(){return pe(this.toKeyedSeq())},toObject:function(){ce(this.size);var e={};return this.__iterate(function(t,n){e[n]=t}),e},toOrderedMap:function(){return Ze(this.toKeyedSeq())},toOrderedSet:function(){return Ut(a(this)?this.valueSeq():this)},toSet:function(){return Nt(a(this)?this.valueSeq():this)},toSetSeq:function(){return new ot(this)},toSeq:function(){return s(this)?this.toIndexedSeq():a(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return Gt(a(this)?this.valueSeq():this)},toList:function(){return Le(a(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(e,t){return 0===this.size?e+t:e+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+t},concat:function(){return Et(this,vt(this,un.call(arguments,0)))},includes:function(e){return this.some(function(t){return X(t,e)})},entries:function(){return this.__iterator(xn)},every:function(e,t){ce(this.size);var n=!0;return this.__iterate(function(r,i,o){if(!e.call(t,r,i,o))return n=!1,!1}),n},filter:function(e,t){return Et(this,ct(this,e,t,!0))},find:function(e,t,n){var r=this.findEntry(e,t);return r?r[1]:n},forEach:function(e,t){return ce(this.size),this.__iterate(t?e.bind(t):e)},join:function(e){ce(this.size),e=void 0!==e?""+e:",";var t="",n=!0;return this.__iterate(function(r){n?n=!1:t+=e,t+=null!==r&&void 0!==r?r.toString():""}),t},keys:function(){return this.__iterator(_n)},map:function(e,t){return Et(this,ut(this,e,t))},reduce:function(e,t,n){ce(this.size);var r,i;return arguments.length<2?i=!0:r=t,this.__iterate(function(t,o,a){i?(i=!1,r=t):r=e.call(n,r,t,o,a)}),r},reduceRight:function(e,t,n){var r=this.toKeyedSeq().reverse();return r.reduce.apply(r,arguments)},reverse:function(){return Et(this,lt(this,!0))},slice:function(e,t){return Et(this,ht(this,e,t,!0))},some:function(e,t){return!this.every(Qt(e),t)},sort:function(e){return Et(this,bt(this,e))},values:function(){return this.__iterator(bn)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some(function(){return!0})},count:function(e,t){return d(e?this.toSeq().filter(e,t):this)},countBy:function(e,t){return pt(this,e,t)},equals:function(e){return Y(this,e)},entrySeq:function(){var e=this;if(e._cache)return new I(e._cache);var t=e.toSeq().map(Zt).toIndexedSeq();return t.fromEntrySeq=function(){return e.toSeq()},t},filterNot:function(e,t){return this.filter(Qt(e),t)},findEntry:function(e,t,n){var r=n;return this.__iterate(function(n,i,o){if(e.call(t,n,i,o))return r=[i,n],!1}),r},findKey:function(e,t){var n=this.findEntry(e,t);return n&&n[0]},findLast:function(e,t,n){return this.toKeyedSeq().reverse().find(e,t,n)},findLastEntry:function(e,t,n){return this.toKeyedSeq().reverse().findEntry(e,t,n)},findLastKey:function(e,t){return this.toKeyedSeq().reverse().findKey(e,t)},first:function(){return this.find(v)},flatMap:function(e,t){return Et(this,yt(this,e,t))},flatten:function(e){return Et(this,gt(this,e,!0))},fromEntrySeq:function(){return new at(this)},get:function(e,t){return this.find(function(t,n){return X(n,e)},void 0,t)},getIn:function(e,t){for(var n,r=this,i=Tt(e);!(n=i.next()).done;){var o=n.value;if((r=r&&r.get?r.get(o,vn):vn)===vn)return t}return r},groupBy:function(e,t){return ft(this,e,t)},has:function(e){return this.get(e,vn)!==vn},hasIn:function(e){return this.getIn(e,vn)!==vn},isSubset:function(e){return e="function"==typeof e.includes?e:t(e),this.every(function(t){return e.includes(t)})},isSuperset:function(e){return e="function"==typeof e.isSubset?e:t(e),e.isSubset(this)},keyOf:function(e){return this.findKey(function(t){return X(t,e)})},keySeq:function(){return this.toSeq().map($t).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},lastKeyOf:function(e){return this.toKeyedSeq().reverse().keyOf(e)},max:function(e){return xt(this,e)},maxBy:function(e,t){return xt(this,t,e)},min:function(e){return xt(this,e?en(e):rn)},minBy:function(e,t){return xt(this,t?en(t):rn,e)},rest:function(){return this.slice(1)},skip:function(e){return this.slice(Math.max(0,e))},skipLast:function(e){return Et(this,this.toSeq().reverse().skip(e).reverse())},skipWhile:function(e,t){return Et(this,mt(this,e,t,!0))},skipUntil:function(e,t){return this.skipWhile(Qt(e),t)},sortBy:function(e,t){return Et(this,bt(this,t,e))},take:function(e){return this.slice(0,Math.max(0,e))},takeLast:function(e){return Et(this,this.toSeq().reverse().take(e).reverse())},takeWhile:function(e,t){return Et(this,dt(this,e,t))},takeUntil:function(e,t){return this.takeWhile(Qt(e),t)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=on(this))}});var ar=t.prototype;ar[ln]=!0,ar[En]=ar.values,ar.__toJS=ar.toArray,ar.__toStringMapper=tn,ar.inspect=ar.toSource=function(){return this.toString()},ar.chain=ar.flatMap,ar.contains=ar.includes,Yt(n,{flip:function(){return Et(this,st(this))},mapEntries:function(e,t){var n=this,r=0;return Et(this,this.toSeq().map(function(i,o){return e.call(t,[o,i],r++,n)}).fromEntrySeq())},mapKeys:function(e,t){var n=this;return Et(this,this.toSeq().flip().map(function(r,i){return e.call(t,r,i,n)}).flip())}});var sr=n.prototype;return sr[cn]=!0,sr[En]=ar.entries,sr.__toJS=ar.toObject,sr.__toStringMapper=function(e,t){return JSON.stringify(t)+": "+tn(e)},Yt(r,{toKeyedSeq:function(){return new rt(this,!1)},filter:function(e,t){return Et(this,ct(this,e,t,!1))},findIndex:function(e,t){var n=this.findEntry(e,t);return n?n[0]:-1},indexOf:function(e){var t=this.keyOf(e);return void 0===t?-1:t},lastIndexOf:function(e){var t=this.lastKeyOf(e);return void 0===t?-1:t},reverse:function(){return Et(this,lt(this,!1))},slice:function(e,t){return Et(this,ht(this,e,t,!1))},splice:function(e,t){var n=arguments.length;if(t=Math.max(0|t,0),0===n||2===n&&!t)return this;e=y(e,e<0?this.count():this.size);var r=this.slice(0,e);return Et(this,1===n?r:r.concat(h(arguments,2),this.slice(e+t)))},findLastIndex:function(e,t){var n=this.findLastEntry(e,t);return n?n[0]:-1},first:function(){return this.get(0)},flatten:function(e){return Et(this,gt(this,e,!1))},get:function(e,t){return e=m(this,e),e<0||this.size===1/0||void 0!==this.size&&e>this.size?t:this.find(function(t,n){return n===e},void 0,t)},has:function(e){return(e=m(this,e))>=0&&(void 0!==this.size?this.size===1/0||e5e3)return e.textContent;return function(e){for(var n,r,i,o,a,s=e.textContent,u=0,l=s[0],c=1,p=e.innerHTML="",f=0;r=n,n=f<7&&"\\"==n?1:c;){if(c=l,l=s[++u],o=p.length>1,!c||f>8&&"\n"==c||[/\S/.test(c),1,1,!/[$\w]/.test(c),("/"==n||"\n"==n)&&o,'"'==n&&o,"'"==n&&o,s[u-4]+r+n=="--\x3e",r+n=="*/"][f])for(p&&(e.appendChild(a=t.createElement("span")).setAttribute("style",["color: #555; font-weight: bold;","","","color: #555;",""][f?f<3?2:f>6?4:f>3?3:+/^(a(bstract|lias|nd|rguments|rray|s(m|sert)?|uto)|b(ase|egin|ool(ean)?|reak|yte)|c(ase|atch|har|hecked|lass|lone|ompl|onst|ontinue)|de(bugger|cimal|clare|f(ault|er)?|init|l(egate|ete)?)|do|double|e(cho|ls?if|lse(if)?|nd|nsure|num|vent|x(cept|ec|p(licit|ort)|te(nds|nsion|rn)))|f(allthrough|alse|inal(ly)?|ixed|loat|or(each)?|riend|rom|unc(tion)?)|global|goto|guard|i(f|mp(lements|licit|ort)|n(it|clude(_once)?|line|out|stanceof|t(erface|ernal)?)?|s)|l(ambda|et|ock|ong)|m(icrolight|odule|utable)|NaN|n(amespace|ative|ext|ew|il|ot|ull)|o(bject|perator|r|ut|verride)|p(ackage|arams|rivate|rotected|rotocol|ublic)|r(aise|e(adonly|do|f|gister|peat|quire(_once)?|scue|strict|try|turn))|s(byte|ealed|elf|hort|igned|izeof|tatic|tring|truct|ubscript|uper|ynchronized|witch)|t(emplate|hen|his|hrows?|ransient|rue|ry|ype(alias|def|id|name|of))|u(n(checked|def(ined)?|ion|less|signed|til)|se|sing)|v(ar|irtual|oid|olatile)|w(char_t|hen|here|hile|ith)|xor|yield)$/.test(p):0]),a.appendChild(t.createTextNode(p))),i=f&&f<7?f:i,p="",f=11;![1,/[\/{}[(\-+*=<>:;|\\.,?!&@~]/.test(c),/[\])]/.test(c),/[$\w]/.test(c),"/"==c&&i<2&&"<"!=n,'"'==c,"'"==c,c+l+s[u+1]+s[u+2]=="\x3c!--",c+l=="/*",c+l=="//","#"==c][--f];);p+=c}}(e)}function b(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"key",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:B.default.Map();if(!B.default.Map.isMap(e)||!e.size)return B.default.List();if(Array.isArray(t)||(t=[t]),t.length<1)return e.merge(n);var r=B.default.List(),i=t[0],o=!0,a=!1,s=void 0;try{for(var u,l=(0,M.default)(e.entries());!(o=(u=l.next()).done);o=!0){var c=u.value,p=(0,D.default)(c,2),f=p[0],h=p[1],d=b(h,t.slice(1),n.set(i,f));r=B.default.List.isList(d)?r.concat(d):r.push(d)}}catch(e){a=!0,s=e}finally{try{!o&&l.return&&l.return()}finally{if(a)throw s}}return r}function x(e){return(0,W.default)((0,z.default)(e))}function w(e){return x(e.replace(/\.[^.\/]*$/,""))}function k(e){return"string"!=typeof e||""===e?"":(0,L.sanitizeUrl)(e)}function E(e){if(!B.default.OrderedMap.isOrderedMap(e))return null;if(!e.size)return null;var t=e.find(function(e,t){return t.startsWith("2")&&(0,R.default)(e.get("content")||{}).length>0}),n=e.get("default")||B.default.OrderedMap(),r=(n.get("content")||B.default.OrderedMap()).keySeq().toJS(),i=r.length?n:null;return t||i}Object.defineProperty(t,"__esModule",{value:!0}),t.getExtensions=t.escapeDeepLinkPath=t.createDeepLinkPath=t.shallowEqualKeys=t.buildFormData=t.sorters=t.btoa=t.parseSearch=t.getSampleSchema=t.validateParam=t.validatePattern=t.validateMinLength=t.validateMaxLength=t.validateGuid=t.validateDateTime=t.validateString=t.validateBoolean=t.validateFile=t.validateInteger=t.validateNumber=t.validateMinimum=t.validateMaximum=t.propChecker=t.errorLog=t.memoize=t.isImmutable=void 0;var S=n(35),C=r(S),A=n(17),D=r(A),O=n(96),M=r(O),T=n(36),P=r(T),I=n(47),R=r(I),j=n(48),F=r(j);t.isJSONObject=i,t.objectify=o,t.arrayify=a,t.fromJSOrdered=s,t.bindToState=u,t.normalizeArray=l,t.isFn=c,t.isObject=p,t.isFunc=f,t.isArray=h,t.objMap=d,t.objReduce=m,t.systemThunkMiddleware=v,t.defaultStatusCode=g,t.getList=y,t.highlight=_,t.mapToList=b,t.pascalCase=x,t.pascalCaseFilename=w,t.sanitizeUrl=k,t.getAcceptControllingResponse=E;var N=n(8),B=r(N),L=n(503),q=n(944),z=r(q),U=n(426),W=r(U),V=n(423),H=r(V),G=n(225),J=r(G),K=n(960),X=r(K),Y=n(120),$=r(Y),Z=n(171),Q=n(53),ee=r(Q),te=n(700),ne=r(te),re="default",ie=t.isImmutable=function(e){return B.default.Iterable.isIterable(e)},oe=(t.memoize=H.default,t.errorLog=function(e){return function(){return function(t){return function(n){try{t(n)}catch(t){e().errActions.newThrownErr(t,n)}}}}},t.propChecker=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[];return(0,R.default)(e).length!==(0,R.default)(t).length||((0,X.default)(e,function(e,n){if(r.includes(n))return!1;var i=t[n];return B.default.Iterable.isIterable(e)?!B.default.is(e,i):("object"!==(void 0===e?"undefined":(0,F.default)(e))||"object"!==(void 0===i?"undefined":(0,F.default)(i)))&&e!==i})||n.some(function(n){return!(0,$.default)(e[n],t[n])}))},t.validateMaximum=function(e,t){if(e>t)return"Value must be less than Maximum"}),ae=t.validateMinimum=function(e,t){if(et)return"Value must be less than MaxLength"},me=t.validateMinLength=function(e,t){if(e.length2&&void 0!==arguments[2]&&arguments[2],r=[],i=t&&"body"===e.get("in")?e.get("value_xml"):e.get("value"),o=e.get("required"),a=n?e.get("schema"):e;if(!a)return r;var s=a.get("maximum"),u=a.get("minimum"),l=a.get("type"),c=a.get("format"),p=a.get("maxLength"),f=a.get("minLength"),h=a.get("pattern");if(l&&(o||i)){var d="string"===l&&i,m="array"===l&&Array.isArray(i)&&i.length,v="array"===l&&B.default.List.isList(i)&&i.count(),g="file"===l&&i instanceof ee.default.File,y="boolean"===l&&(i||!1===i),_="number"===l&&(i||0===i),b="integer"===l&&(i||0===i);if(o&&!(d||m||v||g||y||_||b))return r.push("Required field is not provided"),r;if(h){var x=ve(i,h);x&&r.push(x)}if(p||0===p){var w=de(i,p);w&&r.push(w)}if(f){var k=me(i,f);k&&r.push(k)}if(s||0===s){var E=oe(i,s);E&&r.push(E)}if(u||0===u){var S=ae(i,u);S&&r.push(S)}if("string"===l){var C=void 0;if(!(C="date-time"===c?fe(i):"uuid"===c?he(i):pe(i)))return r;r.push(C)}else if("boolean"===l){var A=ce(i);if(!A)return r;r.push(A)}else if("number"===l){var D=se(i);if(!D)return r;r.push(D)}else if("integer"===l){var O=ue(i);if(!O)return r;r.push(O)}else if("array"===l){var M=void 0;if(!i.count())return r;M=a.getIn(["items","type"]),i.forEach(function(e,t){var n=void 0;"number"===M?n=se(e):"integer"===M?n=ue(e):"string"===M&&(n=pe(e)),n&&r.push({index:t,error:n})})}else if("file"===l){var T=le(i);if(!T)return r;r.push(T)}}return r},t.getSampleSchema=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(/xml/.test(t)){if(!e.xml||!e.xml.name){if(e.xml=e.xml||{},!e.$$ref)return e.type||e.items||e.properties||e.additionalProperties?'\n\x3c!-- XML example cannot be generated --\x3e':null;var r=e.$$ref.match(/\S*\/(\S+)$/);e.xml.name=r[1]}return(0,Z.memoizedCreateXMLExample)(e,n)}return(0,C.default)((0,Z.memoizedSampleFromSchema)(e,n),null,2)},t.parseSearch=function(){var e={},t=ee.default.location.search;if(!t)return{};if(""!=t){var n=t.substr(1).split("&");for(var r in n)r=n[r].split("="),e[decodeURIComponent(r[0])]=decodeURIComponent(r[1])}return e},t.btoa=function(t){var n=void 0;return n=t instanceof e?t:new e(t.toString(),"utf-8"),n.toString("base64")},t.sorters={operationsSorter:{alpha:function(e,t){return e.get("path").localeCompare(t.get("path"))},method:function(e,t){return e.get("method").localeCompare(t.get("method"))}},tagsSorter:{alpha:function(e,t){return e.localeCompare(t)}}},t.buildFormData=function(e){var t=[];for(var n in e){var r=e[n];void 0!==r&&""!==r&&t.push([n,"=",encodeURIComponent(r).replace(/%20/g,"+")].join(""))}return t.join("&")},t.shallowEqualKeys=function(e,t,n){return!!(0,J.default)(n,function(n){return(0,$.default)(e[n],t[n])})},t.createDeepLinkPath=function(e){return"string"==typeof e||e instanceof String?e.trim().replace(/\s/g,"_"):""});t.escapeDeepLinkPath=function(e){return(0,ne.default)(ge(e))},t.getExtensions=function(e){return e.filter(function(e,t){return/^x-/.test(t)})}}).call(t,n(41).Buffer)},function(e,t,n){"use strict";var r=n(32),i=r;e.exports=i},function(e,t,n){"use strict";function r(e){for(var t=arguments.length-1,n="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,r=0;r6?s-6:0),l=6;l5?l-5:0),p=5;p5?a-5:0),u=5;u key("+c[p]+")"].concat(s));if(h instanceof Error)return h}}return i(t)}function u(e){return a(e,"List",b.List.isList)}function l(e,t,n,r){function o(){for(var i=arguments.length,o=Array(i),u=0;u5?s-5:0),l=5;l5?l-5:0),p=5;p>",w={listOf:u,mapOf:c,orderedMapOf:p,setOf:f,orderedSetOf:h,stackOf:d,iterableOf:m,recordOf:v,shape:y,contains:y,mapContains:_,list:o("List",b.List.isList),map:o("Map",b.Map.isMap),orderedMap:o("OrderedMap",b.OrderedMap.isOrderedMap),set:o("Set",b.Set.isSet),orderedSet:o("OrderedSet",b.OrderedSet.isOrderedSet),stack:o("Stack",b.Stack.isStack),seq:o("Seq",b.Seq.isSeq),record:o("Record",function(e){return e instanceof b.Record}),iterable:o("Iterable",b.Iterable.isIterable)};e.exports=w},function(e,t,n){var r=n(24),i=n(14),o=n(54),a=n(57),s=function(e,t,n){var u,l,c,p=e&s.F,f=e&s.G,h=e&s.S,d=e&s.P,m=e&s.B,v=e&s.W,g=f?i:i[t]||(i[t]={}),y=g.prototype,_=f?r:h?r[t]:(r[t]||{}).prototype;f&&(n=t);for(u in n)(l=!p&&_&&void 0!==_[u])&&u in g||(c=l?_[u]:n[u],g[u]=f&&"function"!=typeof _[u]?n[u]:m&&l?o(c,r):v&&_[u]==c?function(e){var t=function(t,n,r){if(this instanceof e){switch(arguments.length){case 0:return new e;case 1:return new e(t);case 2:return new e(t,n)}return new e(t,n,r)}return e.apply(this,arguments)};return t.prototype=e.prototype,t}(c):d&&"function"==typeof c?o(Function.call,c):c,d&&((g.virtual||(g.virtual={}))[u]=c,e&s.R&&y&&!y[u]&&a(y,u,c)))};s.F=1,s.G=2,s.S=4,s.P=8,s.B=16,s.W=32,s.U=64,s.R=128,e.exports=s},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){"use strict";var r=!("undefined"==typeof window||!window.document||!window.document.createElement),i={canUseDOM:r,canUseWorkers:"undefined"!=typeof Worker,canUseEventListeners:r&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:r&&!!window.screen,isInWorker:!r};e.exports=i},function(e,t,n){"use strict";function r(e){return Object.prototype.toString.call(e)}function i(e){return"[object String]"===r(e)}function o(e,t){return!!e&&d.call(e,t)}function a(e){return[].slice.call(arguments,1).forEach(function(t){if(t){if("object"!=typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach(function(n){e[n]=t[n]})}}),e}function s(e){return e.indexOf("\\")<0?e:e.replace(m,"$1")}function u(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!=(65535&e)&&65534!=(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function l(e){if(e>65535){e-=65536;var t=55296+(e>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}function c(e,t){var n=0;return o(y,t)?y[t]:35===t.charCodeAt(0)&&g.test(t)&&(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10),u(n))?l(n):e}function p(e){return e.indexOf("&")<0?e:e.replace(v,c)}function f(e){return x[e]}function h(e){return _.test(e)?e.replace(b,f):e}var d=Object.prototype.hasOwnProperty,m=/\\([\\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g,v=/&([a-z#][a-z0-9]{1,31});/gi,g=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,y=n(486),_=/[&<>"]/,b=/[&<>"]/g,x={"&":"&","<":"<",">":">",'"':"""};t.assign=a,t.isString=i,t.has=o,t.unescapeMd=s,t.isValidEntityCode=u,t.fromCodePoint=l,t.replaceEntities=p,t.escapeHtml=h},function(e,t,n){"use strict";t.__esModule=!0;var r=n(562),i=function(e){return e&&e.__esModule?e:{default:e}}(r);t.default=function(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t"+i+""};e.exports=function(e,t){var n={};n[e]=t(s),r(r.P+r.F*i(function(){var t=""[e]('"');return t!==t.toLowerCase()||t.split('"').length>3}),"String",n)}},function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){"use strict";function r(e){return function(){return e}}var i=function(){};i.thatReturns=r,i.thatReturnsFalse=r(!1),i.thatReturnsTrue=r(!0),i.thatReturnsNull=r(null),i.thatReturnsThis=function(){return this},i.thatReturnsArgument=function(e){return e},e.exports=i},function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function i(e){if(c===setTimeout)return setTimeout(e,0);if((c===n||!c)&&setTimeout)return c=setTimeout,setTimeout(e,0);try{return c(e,0)}catch(t){try{return c.call(null,e,0)}catch(t){return c.call(this,e,0)}}}function o(e){if(p===clearTimeout)return clearTimeout(e);if((p===r||!p)&&clearTimeout)return p=clearTimeout,clearTimeout(e);try{return p(e)}catch(t){try{return p.call(null,e)}catch(t){return p.call(this,e)}}}function a(){m&&h&&(m=!1,h.length?d=h.concat(d):v=-1,d.length&&s())}function s(){if(!m){var e=i(a);m=!0;for(var t=d.length;t;){for(h=d,d=[];++v1)for(var n=1;n=r())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+r().toString(16)+" bytes");return 0|e}function m(e){return+e!=e&&(e=0),o.alloc(+e)}function v(e,t){if(o.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return V(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return J(e).length;default:if(r)return V(e).length;t=(""+t).toLowerCase(),r=!0}}function g(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if(n>>>=0,t>>>=0,n<=t)return"";for(e||(e="utf8");;)switch(e){case"hex":return P(this,t,n);case"utf8":case"utf-8":return D(this,t,n);case"ascii":return M(this,t,n);case"latin1":case"binary":return T(this,t,n);case"base64":return A(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return I(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function y(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function _(e,t,n,r,i){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=i?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(i)return-1;n=e.length-1}else if(n<0){if(!i)return-1;n=0}if("string"==typeof t&&(t=o.from(t,r)),o.isBuffer(t))return 0===t.length?-1:b(e,t,n,r,i);if("number"==typeof t)return t&=255,o.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):b(e,[t],n,r,i);throw new TypeError("val must be string, number or Buffer")}function b(e,t,n,r,i){function o(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}var a=1,s=e.length,u=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,s/=2,u/=2,n/=2}var l;if(i){var c=-1;for(l=n;ls&&(n=s-u),l=n;l>=0;l--){for(var p=!0,f=0;fi&&(r=i):r=i;var o=t.length;if(o%2!=0)throw new TypeError("Invalid hex string");r>o/2&&(r=o/2);for(var a=0;a239?4:o>223?3:o>191?2:1;if(i+s<=n){var u,l,c,p;switch(s){case 1:o<128&&(a=o);break;case 2:u=e[i+1],128==(192&u)&&(p=(31&o)<<6|63&u)>127&&(a=p);break;case 3:u=e[i+1],l=e[i+2],128==(192&u)&&128==(192&l)&&(p=(15&o)<<12|(63&u)<<6|63&l)>2047&&(p<55296||p>57343)&&(a=p);break;case 4:u=e[i+1],l=e[i+2],c=e[i+3],128==(192&u)&&128==(192&l)&&128==(192&c)&&(p=(15&o)<<18|(63&u)<<12|(63&l)<<6|63&c)>65535&&p<1114112&&(a=p)}}null===a?(a=65533,s=1):a>65535&&(a-=65536,r.push(a>>>10&1023|55296),a=56320|1023&a),r.push(a),i+=s}return O(r)}function O(e){var t=e.length;if(t<=Q)return String.fromCharCode.apply(String,e);for(var n="",r=0;rr)&&(n=r);for(var i="",o=t;on)throw new RangeError("Trying to access beyond buffer length")}function j(e,t,n,r,i,a){if(!o.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>i||te.length)throw new RangeError("Index out of range")}function F(e,t,n,r){t<0&&(t=65535+t+1);for(var i=0,o=Math.min(e.length-n,2);i>>8*(r?i:1-i)}function N(e,t,n,r){t<0&&(t=4294967295+t+1);for(var i=0,o=Math.min(e.length-n,4);i>>8*(r?i:3-i)&255}function B(e,t,n,r,i,o){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function L(e,t,n,r,i){return i||B(e,t,n,4,3.4028234663852886e38,-3.4028234663852886e38),$.write(e,t,n,r,23,4),n+4}function q(e,t,n,r,i){return i||B(e,t,n,8,1.7976931348623157e308,-1.7976931348623157e308),$.write(e,t,n,r,52,8),n+8}function z(e){if(e=U(e).replace(ee,""),e.length<2)return"";for(;e.length%4!=0;)e+="=";return e}function U(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}function W(e){return e<16?"0"+e.toString(16):e.toString(16)}function V(e,t){t=t||1/0;for(var n,r=e.length,i=null,o=[],a=0;a55295&&n<57344){if(!i){if(n>56319){(t-=3)>-1&&o.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&o.push(239,191,189);continue}i=n;continue}if(n<56320){(t-=3)>-1&&o.push(239,191,189),i=n;continue}n=65536+(i-55296<<10|n-56320)}else i&&(t-=3)>-1&&o.push(239,191,189);if(i=null,n<128){if((t-=1)<0)break;o.push(n)}else if(n<2048){if((t-=2)<0)break;o.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;o.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;o.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return o}function H(e){for(var t=[],n=0;n>8,i=n%256,o.push(i),o.push(r);return o}function J(e){return Y.toByteArray(z(e))}function K(e,t,n,r){for(var i=0;i=t.length||i>=e.length);++i)t[i+n]=e[i];return i}function X(e){return e!==e}/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +var Y=n(569),$=n(768),Z=n(386);t.Buffer=o,t.SlowBuffer=m,t.INSPECT_MAX_BYTES=50,o.TYPED_ARRAY_SUPPORT=void 0!==e.TYPED_ARRAY_SUPPORT?e.TYPED_ARRAY_SUPPORT:function(){try{var e=new Uint8Array(1);return e.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42}},42===e.foo()&&"function"==typeof e.subarray&&0===e.subarray(1,1).byteLength}catch(e){return!1}}(),t.kMaxLength=r(),o.poolSize=8192,o._augment=function(e){return e.__proto__=o.prototype,e},o.from=function(e,t,n){return a(null,e,t,n)},o.TYPED_ARRAY_SUPPORT&&(o.prototype.__proto__=Uint8Array.prototype,o.__proto__=Uint8Array,"undefined"!=typeof Symbol&&Symbol.species&&o[Symbol.species]===o&&Object.defineProperty(o,Symbol.species,{value:null,configurable:!0})),o.alloc=function(e,t,n){return u(null,e,t,n)},o.allocUnsafe=function(e){return l(null,e)},o.allocUnsafeSlow=function(e){return l(null,e)},o.isBuffer=function(e){return!(null==e||!e._isBuffer)},o.compare=function(e,t){if(!o.isBuffer(e)||!o.isBuffer(t))throw new TypeError("Arguments must be Buffers");if(e===t)return 0;for(var n=e.length,r=t.length,i=0,a=Math.min(n,r);i0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},o.prototype.compare=function(e,t,n,r,i){if(!o.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===i&&(i=this.length),t<0||n>e.length||r<0||i>this.length)throw new RangeError("out of range index");if(r>=i&&t>=n)return 0;if(r>=i)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,r>>>=0,i>>>=0,this===e)return 0;for(var a=i-r,s=n-t,u=Math.min(a,s),l=this.slice(r,i),c=e.slice(t,n),p=0;pi)&&(n=i),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var o=!1;;)switch(r){case"hex":return x(this,e,t,n);case"utf8":case"utf-8":return w(this,e,t,n);case"ascii":return k(this,e,t,n);case"latin1":case"binary":return E(this,e,t,n);case"base64":return S(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return C(this,e,t,n);default:if(o)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),o=!0}},o.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var Q=4096;o.prototype.slice=function(e,t){var n=this.length;e=~~e,t=void 0===t?n:~~t,e<0?(e+=n)<0&&(e=0):e>n&&(e=n),t<0?(t+=n)<0&&(t=0):t>n&&(t=n),t0&&(i*=256);)r+=this[e+--t]*i;return r},o.prototype.readUInt8=function(e,t){return t||R(e,1,this.length),this[e]},o.prototype.readUInt16LE=function(e,t){return t||R(e,2,this.length),this[e]|this[e+1]<<8},o.prototype.readUInt16BE=function(e,t){return t||R(e,2,this.length),this[e]<<8|this[e+1]},o.prototype.readUInt32LE=function(e,t){return t||R(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},o.prototype.readUInt32BE=function(e,t){return t||R(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},o.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||R(e,t,this.length);for(var r=this[e],i=1,o=0;++o=i&&(r-=Math.pow(2,8*t)),r},o.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||R(e,t,this.length);for(var r=t,i=1,o=this[e+--r];r>0&&(i*=256);)o+=this[e+--r]*i;return i*=128,o>=i&&(o-=Math.pow(2,8*t)),o},o.prototype.readInt8=function(e,t){return t||R(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},o.prototype.readInt16LE=function(e,t){t||R(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt16BE=function(e,t){t||R(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt32LE=function(e,t){return t||R(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},o.prototype.readInt32BE=function(e,t){return t||R(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},o.prototype.readFloatLE=function(e,t){return t||R(e,4,this.length),$.read(this,e,!0,23,4)},o.prototype.readFloatBE=function(e,t){return t||R(e,4,this.length),$.read(this,e,!1,23,4)},o.prototype.readDoubleLE=function(e,t){return t||R(e,8,this.length),$.read(this,e,!0,52,8)},o.prototype.readDoubleBE=function(e,t){return t||R(e,8,this.length),$.read(this,e,!1,52,8)},o.prototype.writeUIntLE=function(e,t,n,r){if(e=+e,t|=0,n|=0,!r){j(this,e,t,n,Math.pow(2,8*n)-1,0)}var i=1,o=0;for(this[t]=255&e;++o=0&&(o*=256);)this[t+i]=e/o&255;return t+n},o.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,1,255,0),o.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},o.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,2,65535,0),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):F(this,e,t,!0),t+2},o.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,2,65535,0),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):F(this,e,t,!1),t+2},o.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,4,4294967295,0),o.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):N(this,e,t,!0),t+4},o.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,4,4294967295,0),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},o.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);j(this,e,t,n,i-1,-i)}var o=0,a=1,s=0;for(this[t]=255&e;++o>0)-s&255;return t+n},o.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);j(this,e,t,n,i-1,-i)}var o=n-1,a=1,s=0;for(this[t+o]=255&e;--o>=0&&(a*=256);)e<0&&0===s&&0!==this[t+o+1]&&(s=1),this[t+o]=(e/a>>0)-s&255;return t+n},o.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,1,127,-128),o.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},o.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,2,32767,-32768),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):F(this,e,t,!0),t+2},o.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,2,32767,-32768),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):F(this,e,t,!1),t+2},o.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,4,2147483647,-2147483648),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):N(this,e,t,!0),t+4},o.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||j(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},o.prototype.writeFloatLE=function(e,t,n){return L(this,e,t,!0,n)},o.prototype.writeFloatBE=function(e,t,n){return L(this,e,t,!1,n)},o.prototype.writeDoubleLE=function(e,t,n){return q(this,e,t,!0,n)},o.prototype.writeDoubleBE=function(e,t,n){return q(this,e,t,!1,n)},o.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--i)e[i+t]=this[i+n];else if(a<1e3||!o.TYPED_ARRAY_SUPPORT)for(i=0;i>>=0,n=void 0===n?this.length:n>>>0,e||(e=0);var a;if("number"==typeof e)for(a=t;a0&&(a=this.buffer[u-1],e.call(r,a)<0);)if(u--,this.pointer-u>n/2-1){o=" ... ",u+=5;break}for(l="",i=this.pointer;in/2-1){l=" ... ",i-=5;break}return""+new Array(t).join(" ")+o+this.buffer.slice(u,i)+l+"\n"+new Array(t+this.pointer-u+o.length).join(" ")+"^"},t.prototype.toString=function(){var e,t;return e=this.get_snippet(),t=" on line "+(this.line+1)+", column "+(this.column+1),e?t:t+":\n"+e},t}(),this.YAMLError=function(e){function n(e){this.message=e,n.__super__.constructor.call(this),this.stack=this.toString()+"\n"+(new Error).stack.split("\n").slice(1).join("\n")}return t(n,e),n.prototype.toString=function(){return this.message},n}(Error),this.MarkedYAMLError=function(e){function n(e,t,r,i,o){this.context=e,this.context_mark=t,this.problem=r,this.problem_mark=i,this.note=o,n.__super__.constructor.call(this)}return t(n,e),n.prototype.toString=function(){var e;return e=[],null!=this.context&&e.push(this.context),null==this.context_mark||null!=this.problem&&null!=this.problem_mark&&this.context_mark.line===this.problem_mark.line&&this.context_mark.column===this.problem_mark.column||e.push(this.context_mark.toString()),null!=this.problem&&e.push(this.problem),null!=this.problem_mark&&e.push(this.problem_mark.toString()),null!=this.note&&e.push(this.note),e.join("\n")},n}(this.YAMLError)}).call(this)},function(e,t,n){e.exports={default:n(596),__esModule:!0}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(566),o=r(i),a=n(565),s=r(a),u="function"==typeof s.default&&"symbol"==typeof o.default?function(e){return typeof e}:function(e){return e&&"function"==typeof s.default&&e.constructor===s.default&&e!==s.default.prototype?"symbol":typeof e};t.default="function"==typeof s.default&&"symbol"===u(o.default)?function(e){return void 0===e?"undefined":u(e)}:function(e){return e&&"function"==typeof s.default&&e.constructor===s.default&&e!==s.default.prototype?"symbol":void 0===e?"undefined":u(e)}},function(e,t,n){e.exports=!n(55)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t,n){"use strict";function r(e,t,n){return n?[e,t]:e}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r,e.exports=t.default},function(e,t,n){"use strict";function r(e,t,n,r){this.dispatchConfig=e,this._targetInst=t,this.nativeEvent=n;var i=this.constructor.Interface;for(var o in i)if(i.hasOwnProperty(o)){var s=i[o];s?this[o]=s(n):"target"===o?this.target=r:this[o]=n[o]}var u=null!=n.defaultPrevented?n.defaultPrevented:!1===n.returnValue;return this.isDefaultPrevented=u?a.thatReturnsTrue:a.thatReturnsFalse,this.isPropagationStopped=a.thatReturnsFalse,this}var i=n(12),o=n(71),a=n(32),s=(n(10),["dispatchConfig","_targetInst","nativeEvent","isDefaultPrevented","isPropagationStopped","_dispatchListeners","_dispatchInstances"]),u={type:null,target:null,currentTarget:a.thatReturnsNull,eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null};i(r.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=a.thatReturnsTrue)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=a.thatReturnsTrue)},persist:function(){this.isPersistent=a.thatReturnsTrue},isPersistent:a.thatReturnsFalse,destructor:function(){var e=this.constructor.Interface;for(var t in e)this[t]=null;for(var n=0;n1?t-1:0),i=1;i2?n-2:0),o=2;o=n?e:e.length+1===n?""+t+e:""+new Array(n-e.length+1).join(t)+e},this.to_hex=function(e){return"string"==typeof e&&(e=e.charCodeAt(0)),e.toString(16)}}).call(this)}).call(t,n(16))},function(e,t,n){var r=n(78);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t){var n=e.exports={version:"2.5.1"};"number"==typeof __e&&(__e=n)},function(e,t,n){var r=n(138),i=n(359);e.exports=n(106)?function(e,t,n){return r.f(e,t,i(1,n))}:function(e,t,n){return e[t]=n,e}},function(e,t,n){"use strict";var r=n(729),i=Math.max;e.exports=function(e){return i(0,r(e))}},function(e,t,n){function r(e){return null==e?void 0===e?u:s:(e=Object(e),l&&l in e?o(e):a(e))}var i=n(83),o=n(900),a=n(929),s="[object Null]",u="[object Undefined]",l=i?i.toStringTag:void 0;e.exports=r},function(e,t,n){function r(e,t){var n=o(e,t);return i(n)?n:void 0}var i=n(858),o=n(901);e.exports=r},function(e,t){function n(e){return null!=e&&"object"==typeof e}e.exports=n},function(e,t,n){"use strict"},function(e,t,n){"use strict";var r=n(11),i=(n(7),function(e){var t=this;if(t.instancePool.length){var n=t.instancePool.pop();return t.call(n,e),n}return new t(e)}),o=function(e,t){var n=this;if(n.instancePool.length){var r=n.instancePool.pop();return n.call(r,e,t),r}return new n(e,t)},a=function(e,t,n){var r=this;if(r.instancePool.length){var i=r.instancePool.pop();return r.call(i,e,t,n),i}return new r(e,t,n)},s=function(e,t,n,r){var i=this;if(i.instancePool.length){var o=i.instancePool.pop();return i.call(o,e,t,n,r),o}return new i(e,t,n,r)},u=function(e){var t=this;e instanceof t||r("25"),e.destructor(),t.instancePool.length`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*/?>",u="]",l=new RegExp("^(?:<[A-Za-z][A-Za-z0-9-]*(?:\\s+[a-zA-Z_:][a-zA-Z0-9:._-]*(?:\\s*=\\s*(?:[^\"'=<>`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*/?>|]|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|[<][?].*?[?][>]|]*>|)","i"),c=/[\\&]/,p="[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]",f=new RegExp("\\\\"+p+"|"+a,"gi"),h=new RegExp('[&<>"]',"g"),d=new RegExp(a+'|[&<>"]',"gi"),m=function(e){return 92===e.charCodeAt(0)?e.charAt(1):o(e)},v=function(e){return c.test(e)?e.replace(f,m):e},g=function(e){try{return r(i(e))}catch(t){return e}},y=function(e){switch(e){case"&":return"&";case"<":return"<";case">":return">";case'"':return""";default:return e}},_=function(e,t){return h.test(e)?t?e.replace(d,y):e.replace(h,y):e};e.exports={unescapeString:v,normalizeURI:g,escapeXml:_,reHtmlTag:l,OPENTAG:s,CLOSETAG:u,ENTITY:a,ESCAPABLE:p}},function(e,t){e.exports={}},function(e,t,n){var r=n(183),i=n(180);e.exports=function(e){return r(i(e))}},function(e,t,n){var r=n(180);e.exports=function(e){return Object(r(e))}},function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t,n){var r=n(31),i=n(65),o=n(108),a=n(204)("src"),s=Function.toString,u=(""+s).split("toString");n(64).inspectSource=function(e){return s.call(e)},(e.exports=function(e,t,n,s){var l="function"==typeof n;l&&(o(n,"name")||i(n,"name",t)),e[t]!==n&&(l&&(o(n,a)||i(n,a,e[t]?""+e[t]:u.join(String(t)))),e===r?e[t]=n:s?e[t]?e[t]=n:i(e,t,n):(delete e[t],i(e,t,n)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[a]||s.call(this)})},function(e,t,n){"use strict";var r=n(371)();e.exports=function(e){return e!==r&&null!==e}},function(e,t,n){"use strict";function r(e){return void 0===e||null===e}function i(e){return"object"==typeof e&&null!==e}function o(e){return Array.isArray(e)?e:r(e)?[]:[e]}function a(e,t){var n,r,i,o;if(t)for(o=Object.keys(t),n=0,r=o.length;n`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*/?>",u="]",l=new RegExp("^(?:<[A-Za-z][A-Za-z0-9-]*(?:\\s+[a-zA-Z_:][a-zA-Z0-9:._-]*(?:\\s*=\\s*(?:[^\"'=<>`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*/?>|]|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|[<][?].*?[?][>]|]*>|)","i"),c=/[\\&]/,p="[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]",f=new RegExp("\\\\"+p+"|"+a,"gi"),h=new RegExp('[&<>"]',"g"),d=new RegExp(a+'|[&<>"]',"gi"),m=function(e){return 92===e.charCodeAt(0)?e.charAt(1):o(e)},v=function(e){return c.test(e)?e.replace(f,m):e},g=function(e){try{return r(i(e))}catch(t){return e}},y=function(e){switch(e){case"&":return"&";case"<":return"<";case">":return">";case'"':return""";default:return e}},_=function(e,t){return h.test(e)?t?e.replace(d,y):e.replace(h,y):e};e.exports={unescapeString:v,normalizeURI:g,escapeXml:_,reHtmlTag:l,OPENTAG:s,CLOSETAG:u,ENTITY:a,ESCAPABLE:p}},function(e,t,n){"use strict";var r=n(12),i=n(472),o=n(1104),a=n(1105),s=n(94),u=n(1106),l=n(1107),c=n(1108),p=n(1112),f=s.createElement,h=s.createFactory,d=s.cloneElement,m=r,v=function(e){return e},g={Children:{map:o.map,forEach:o.forEach,count:o.count,toArray:o.toArray,only:p},Component:i.Component,PureComponent:i.PureComponent,createElement:f,cloneElement:d,isValidElement:s.isValidElement,PropTypes:u,createClass:c,createFactory:h,createMixin:v,DOM:a,version:l,__spread:m};e.exports=g},function(e,t,n){"use strict";function r(e){return void 0!==e.ref}function i(e){return void 0!==e.key}var o=n(12),a=n(52),s=(n(10),n(476),Object.prototype.hasOwnProperty),u=n(474),l={key:!0,ref:!0,__self:!0,__source:!0},c=function(e,t,n,r,i,o,a){var s={$$typeof:u,type:e,key:t,ref:n,props:a,_owner:o};return s};c.createElement=function(e,t,n){var o,u={},p=null,f=null;if(null!=t){r(t)&&(f=t.ref),i(t)&&(p=""+t.key),void 0===t.__self?null:t.__self,void 0===t.__source?null:t.__source;for(o in t)s.call(t,o)&&!l.hasOwnProperty(o)&&(u[o]=t[o])}var h=arguments.length-2;if(1===h)u.children=n;else if(h>1){for(var d=Array(h),m=0;m1){for(var g=Array(v),y=0;y=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}},function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},function(e,t,n){var r=n(344),i=n(182);e.exports=Object.keys||function(e){return r(e,i)}},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){var r=n(42).f,i=n(56),o=n(21)("toStringTag");e.exports=function(e,t,n){e&&!i(e=n?e:e.prototype,o)&&r(e,o,{configurable:!0,value:t})}},function(e,t,n){"use strict";var r=n(620)(!0);n(338)(String,"String",function(e){this._t=String(e),this._i=0},function(){var e,t=this._t,n=this._i;return n>=t.length?{value:void 0,done:!0}:(e=r(t,n),this._i+=e.length,{value:e,done:!1})})},function(e,t,n){n(625);for(var r=n(24),i=n(57),o=n(75),a=n(21)("toStringTag"),s="CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,TextTrackList,TouchList".split(","),u=0;u0?i(r(e),9007199254740991):0}},function(e,t,n){(function(e){function n(e){return Array.isArray?Array.isArray(e):"[object Array]"===v(e)}function r(e){return"boolean"==typeof e}function i(e){return null===e}function o(e){return null==e}function a(e){return"number"==typeof e}function s(e){return"string"==typeof e}function u(e){return"symbol"==typeof e}function l(e){return void 0===e}function c(e){return"[object RegExp]"===v(e)}function p(e){return"object"==typeof e&&null!==e}function f(e){return"[object Date]"===v(e)}function h(e){return"[object Error]"===v(e)||e instanceof Error}function d(e){return"function"==typeof e}function m(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e}function v(e){return Object.prototype.toString.call(e)}t.isArray=n,t.isBoolean=r,t.isNull=i,t.isNullOrUndefined=o,t.isNumber=a,t.isString=s,t.isSymbol=u,t.isUndefined=l,t.isRegExp=c,t.isObject=p,t.isDate=f,t.isError=h,t.isFunction=d,t.isPrimitive=m,t.isBuffer=e.isBuffer}).call(t,n(41).Buffer)},function(e,t,n){"use strict";function r(e){return"string"==typeof e&&i.test(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=/-webkit-|-moz-|-ms-/;e.exports=t.default},function(e,t){e.exports={Text:"text",Directive:"directive",Comment:"comment",Script:"script",Style:"style",Tag:"tag",CDATA:"cdata",Doctype:"doctype",isTag:function(e){return"tag"===e.type||"script"===e.type||"style"===e.type}}},function(e,t,n){var r=n(715),i=n(714);t.decode=function(e,t){return(!t||t<=0?i.XML:i.HTML)(e)},t.decodeStrict=function(e,t){return(!t||t<=0?i.XML:i.HTMLStrict)(e)},t.encode=function(e,t){return(!t||t<=0?r.XML:r.HTML)(e)},t.encodeXML=r.XML,t.encodeHTML4=t.encodeHTML5=t.encodeHTML=r.HTML,t.decodeXML=t.decodeXMLStrict=i.XML,t.decodeHTML4=t.decodeHTML5=t.decodeHTML=i.HTML,t.decodeHTML4Strict=t.decodeHTML5Strict=t.decodeHTMLStrict=i.HTMLStrict,t.escape=r.escape},function(e,t,n){"use strict";var r=n(80);e.exports=function(e){if(!r(e))throw new TypeError("Cannot use null or undefined");return e}},function(e,t,n){function r(t,n){return delete e.exports[t],e.exports[t]=n,n}var i=n(379),o=n(703);e.exports={Parser:i,Tokenizer:n(380),ElementType:n(113),DomHandler:o,get FeedHandler(){return r("FeedHandler",n(764))},get Stream(){return r("Stream",n(766))},get WritableStream(){return r("WritableStream",n(381))},get ProxyHandler(){return r("ProxyHandler",n(765))},get DomUtils(){return r("DomUtils",n(705))},get CollectingHandler(){return r("CollectingHandler",n(763))},DefaultHandler:o,get RssHandler(){return r("RssHandler",this.FeedHandler)},parseDOM:function(e,t){var n=new o(t);return new i(n,t).end(e),n.dom},parseFeed:function(t,n){var r=new e.exports.FeedHandler(n);return new i(r,n).end(t),r.dom},createDomStream:function(e,t,n){var r=new o(e,t,n);return new i(r,t)},EVENTS:{attribute:2,cdatastart:0,cdataend:0,text:1,processinginstruction:2,comment:1,commentend:0,closetag:1,opentag:2,opentagname:1,error:1,end:0}}},function(e,t,n){"use strict";function r(e,t){Error.call(this),this.name="YAMLException",this.reason=e,this.mark=t,this.message=(this.reason||"(unknown reason)")+(this.mark?" "+this.mark.toString():""),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack||""}r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r.prototype.toString=function(e){var t=this.name+": ";return t+=this.reason||"(unknown reason)",!e&&this.mark&&(t+=" "+this.mark.toString()),t},e.exports=r},function(e,t,n){"use strict";var r=n(82);e.exports=new r({include:[n(387)],implicit:[n(818),n(811)],explicit:[n(803),n(813),n(814),n(816)]})},function(e,t,n){function r(e){return"function"==typeof e?e:null==e?a:"object"==typeof e?s(e)?o(e[0],e[1]):i(e):u(e)}var i=n(862),o=n(863),a=n(227),s=n(19),u=n(957);e.exports=r},function(e,t){function n(e,t){return e===t||e!==e&&t!==t}e.exports=n},function(e,t){function n(e,t,n){if(t in e)return e[t];if(3===arguments.length)return n;throw new Error('"'+t+'" is a required argument.')}function r(e){var t=e.match(y);return t?{scheme:t[1],auth:t[2],host:t[3],port:t[4],path:t[5]}:null}function i(e){var t="";return e.scheme&&(t+=e.scheme+":"),t+="//",e.auth&&(t+=e.auth+"@"),e.host&&(t+=e.host),e.port&&(t+=":"+e.port),e.path&&(t+=e.path),t}function o(e){var n=e,o=r(e);if(o){if(!o.path)return e;n=o.path}for(var a,s=t.isAbsolute(n),u=n.split(/\/+/),l=0,c=u.length-1;c>=0;c--)a=u[c],"."===a?u.splice(c,1):".."===a?l++:l>0&&(""===a?(u.splice(c+1,l),l=0):(u.splice(c,2),l--));return n=u.join("/"),""===n&&(n=s?"/":"."),o?(o.path=n,i(o)):n}function a(e,t){""===e&&(e="."),""===t&&(t=".");var n=r(t),a=r(e);if(a&&(e=a.path||"/"),n&&!n.scheme)return a&&(n.scheme=a.scheme),i(n);if(n||t.match(_))return t;if(a&&!a.host&&!a.path)return a.host=t,i(a);var s="/"===t.charAt(0)?t:o(e.replace(/\/+$/,"")+"/"+t);return a?(a.path=s,i(a)):s}function s(e,t){""===e&&(e="."),e=e.replace(/\/$/,"");for(var n=0;0!==t.indexOf(e+"/");){var r=e.lastIndexOf("/");if(r<0)return t;if(e=e.slice(0,r),e.match(/^([^\/]+:\/)?\/*$/))return t;++n}return Array(n+1).join("../")+t.substr(e.length+1)}function u(e){return e}function l(e){return p(e)?"$"+e:e}function c(e){return p(e)?e.slice(1):e}function p(e){if(!e)return!1;var t=e.length;if(t<9)return!1;if(95!==e.charCodeAt(t-1)||95!==e.charCodeAt(t-2)||111!==e.charCodeAt(t-3)||116!==e.charCodeAt(t-4)||111!==e.charCodeAt(t-5)||114!==e.charCodeAt(t-6)||112!==e.charCodeAt(t-7)||95!==e.charCodeAt(t-8)||95!==e.charCodeAt(t-9))return!1;for(var n=t-10;n>=0;n--)if(36!==e.charCodeAt(n))return!1;return!0}function f(e,t,n){var r=d(e.source,t.source);return 0!==r?r:0!==(r=e.originalLine-t.originalLine)?r:0!==(r=e.originalColumn-t.originalColumn)||n?r:0!==(r=e.generatedColumn-t.generatedColumn)?r:(r=e.generatedLine-t.generatedLine,0!==r?r:d(e.name,t.name))}function h(e,t,n){var r=e.generatedLine-t.generatedLine;return 0!==r?r:0!==(r=e.generatedColumn-t.generatedColumn)||n?r:0!==(r=d(e.source,t.source))?r:0!==(r=e.originalLine-t.originalLine)?r:(r=e.originalColumn-t.originalColumn,0!==r?r:d(e.name,t.name))}function d(e,t){return e===t?0:null===e?1:null===t?-1:e>t?1:-1}function m(e,t){var n=e.generatedLine-t.generatedLine;return 0!==n?n:0!==(n=e.generatedColumn-t.generatedColumn)?n:0!==(n=d(e.source,t.source))?n:0!==(n=e.originalLine-t.originalLine)?n:(n=e.originalColumn-t.originalColumn,0!==n?n:d(e.name,t.name))}function v(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}function g(e,t,n){if(t=t||"",e&&("/"!==e[e.length-1]&&"/"!==t[0]&&(e+="/"),t=e+t),n){var s=r(n);if(!s)throw new Error("sourceMapURL could not be parsed");if(s.path){var u=s.path.lastIndexOf("/");u>=0&&(s.path=s.path.substring(0,u+1))}t=a(i(s),t)}return o(t)}t.getArg=n;var y=/^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/,_=/^data:.+\,.+$/;t.urlParse=r,t.urlGenerate=i,t.normalize=o,t.join=a,t.isAbsolute=function(e){return"/"===e.charAt(0)||y.test(e)},t.relative=s;var b=function(){return!("__proto__"in Object.create(null))}();t.toSetString=b?u:l,t.fromSetString=b?u:c,t.compareByOriginalPositions=f,t.compareByGeneratedPositionsDeflated=h,t.compareByGeneratedPositionsInflated=m,t.parseSourceMapInput=v,t.computeSourceURL=g},function(e,t,n){"use strict";function r(e){return"button"===e||"input"===e||"select"===e||"textarea"===e}function i(e,t,n){switch(e){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":return!(!n.disabled||!r(t));default:return!1}}var o=n(11),a=n(244),s=n(245),u=n(249),l=n(460),c=n(461),p=(n(7),{}),f=null,h=function(e,t){e&&(s.executeDispatchesInOrder(e,t),e.isPersistent()||e.constructor.release(e))},d=function(e){return h(e,!0)},m=function(e){return h(e,!1)},v=function(e){return"."+e._rootNodeID},g={injection:{injectEventPluginOrder:a.injectEventPluginOrder,injectEventPluginsByName:a.injectEventPluginsByName},putListener:function(e,t,n){"function"!=typeof n&&o("94",t,typeof n);var r=v(e);(p[t]||(p[t]={}))[r]=n;var i=a.registrationNameModules[t];i&&i.didPutListener&&i.didPutListener(e,t,n)},getListener:function(e,t){var n=p[t];if(i(t,e._currentElement.type,e._currentElement.props))return null;var r=v(e);return n&&n[r]},deleteListener:function(e,t){var n=a.registrationNameModules[t];n&&n.willDeleteListener&&n.willDeleteListener(e,t);var r=p[t];if(r){delete r[v(e)]}},deleteAllListeners:function(e){var t=v(e);for(var n in p)if(p.hasOwnProperty(n)&&p[n][t]){var r=a.registrationNameModules[n];r&&r.willDeleteListener&&r.willDeleteListener(e,n),delete p[n][t]}},extractEvents:function(e,t,n,r){for(var i,o=a.plugins,s=0;s0&&void 0!==arguments[0]?arguments[0]:{};return{type:v,payload:e}}Object.defineProperty(t,"__esModule",{value:!0}),t.CLEAR=t.NEW_AUTH_ERR=t.NEW_SPEC_ERR_BATCH=t.NEW_SPEC_ERR=t.NEW_THROWN_ERR_BATCH=t.NEW_THROWN_ERR=void 0,t.newThrownErr=r,t.newThrownErrBatch=i,t.newSpecErr=o,t.newSpecErrBatch=a,t.newAuthErr=s,t.clear=u;var l=n(266),c=function(e){return e&&e.__esModule?e:{default:e}}(l),p=t.NEW_THROWN_ERR="err_new_thrown_err",f=t.NEW_THROWN_ERR_BATCH="err_new_thrown_err_batch",h=t.NEW_SPEC_ERR="err_new_spec_err",d=t.NEW_SPEC_ERR_BATCH="err_new_spec_err_batch",m=t.NEW_AUTH_ERR="err_new_auth_err",v=t.CLEAR="err_clear"},function(e,t,n){var r=n(54),i=n(337),o=n(335),a=n(38),s=n(133),u=n(195),l={},c={},t=e.exports=function(e,t,n,p,f){var h,d,m,v,g=f?function(){return e}:u(e),y=r(n,p,t?2:1),_=0;if("function"!=typeof g)throw TypeError(e+" is not iterable!");if(o(g)){for(h=s(e.length);h>_;_++)if((v=t?y(a(d=e[_])[0],d[1]):y(e[_]))===l||v===c)return v}else for(m=g.call(e);!(d=m.next()).done;)if((v=i(m,y,d.value,t))===l||v===c)return v};t.BREAK=l,t.RETURN=c},function(e,t){e.exports=!0},function(e,t,n){var r=n(134)("meta"),i=n(30),o=n(56),a=n(42).f,s=0,u=Object.isExtensible||function(){return!0},l=!n(55)(function(){return u(Object.preventExtensions({}))}),c=function(e){a(e,r,{value:{i:"O"+ ++s,w:{}}})},p=function(e,t){if(!i(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!o(e,r)){if(!u(e))return"F";if(!t)return"E";c(e)}return e[r].i},f=function(e,t){if(!o(e,r)){if(!u(e))return!0;if(!t)return!1;c(e)}return e[r].w},h=function(e){return l&&d.NEED&&u(e)&&!o(e,r)&&c(e),e},d=e.exports={KEY:r,NEED:!1,fastKey:p,getWeak:f,onFreeze:h}},function(e,t){t.f={}.propertyIsEnumerable},function(e,t,n){var r=n(191),i=Math.min;e.exports=function(e){return e>0?i(r(e),9007199254740991):0}},function(e,t){var n=0,r=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+r).toString(36))}},function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t,n){var r=n(135);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,i){return e.call(t,n,r,i)}}return function(){return e.apply(t,arguments)}}},function(e,t,n){"use strict";var r=n(65),i=n(79),o=n(107),a=n(58),s=n(18);e.exports=function(e,t,n){var u=s(e),l=n(a,u,""[e]),c=l[0],p=l[1];o(function(){var t={};return t[u]=function(){return 7},7!=""[e](t)})&&(i(String.prototype,e,c),r(RegExp.prototype,u,2==t?function(e,t){return p.call(e,this,t)}:function(e){return p.call(e,this)}))}},function(e,t,n){var r=n(63),i=n(645),o=n(664),a=Object.defineProperty;t.f=n(106)?Object.defineProperty:function(e,t,n){if(r(e),t=o(t,!0),r(n),i)try{return a(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},function(e,t){var n=Math.ceil,r=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?r:n)(e)}},function(e,t,n){var r=n(647),i=n(58);e.exports=function(e){return r(i(e))}},function(e,t,n){"use strict";var r,i=n(372),o=n(375),a=n(733),s=n(738);r=e.exports=function(e,t){var n,r,a,u,l;return arguments.length<2||"string"!=typeof e?(u=t,t=e,e=null):u=arguments[2],null==e?(n=a=!0,r=!1):(n=s.call(e,"c"),r=s.call(e,"e"),a=s.call(e,"w")),l={value:t,configurable:n,enumerable:r,writable:a},u?i(o(u),l):l},r.gs=function(e,t,n){var r,u,l,c;return"string"!=typeof e?(l=n,n=t,t=e,e=null):l=arguments[3],null==t?t=void 0:a(t)?null==n?n=void 0:a(n)||(l=n,n=void 0):(l=t,t=n=void 0),null==e?(r=!0,u=!1):(r=s.call(e,"c"),u=s.call(e,"e")),c={get:t,set:n,configurable:r,enumerable:u},l?i(o(l),c):c}},function(e,t,n){"use strict";e.exports=n(730)("forEach")},function(e,t){function n(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(e){return"function"==typeof e}function i(e){return"number"==typeof e}function o(e){return"object"==typeof e&&null!==e}function a(e){return void 0===e}e.exports=n,n.EventEmitter=n,n.prototype._events=void 0,n.prototype._maxListeners=void 0,n.defaultMaxListeners=10,n.prototype.setMaxListeners=function(e){if(!i(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},n.prototype.emit=function(e){var t,n,i,s,u,l;if(this._events||(this._events={}),"error"===e&&(!this._events.error||o(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var c=new Error('Uncaught, unspecified "error" event. ('+t+")");throw c.context=t,c}if(n=this._events[e],a(n))return!1;if(r(n))switch(arguments.length){case 1:n.call(this);break;case 2:n.call(this,arguments[1]);break;case 3:n.call(this,arguments[1],arguments[2]);break;default:s=Array.prototype.slice.call(arguments,1),n.apply(this,s)}else if(o(n))for(s=Array.prototype.slice.call(arguments,1),l=n.slice(),i=l.length,u=0;u0&&this._events[e].length>i&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(e,t){function n(){this.removeListener(e,n),i||(i=!0,t.apply(this,arguments))}if(!r(t))throw TypeError("listener must be a function");var i=!1;return n.listener=t,this.on(e,n),this},n.prototype.removeListener=function(e,t){var n,i,a,s;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(n=this._events[e],a=n.length,i=-1,n===t||r(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(o(n)){for(s=a;s-- >0;)if(n[s]===t||n[s].listener&&n[s].listener===t){i=s;break}if(i<0)return this;1===n.length?(n.length=0,delete this._events[e]):n.splice(i,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},n.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(n=this._events[e],r(n))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},n.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},n.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},n.listenerCount=function(e,t){return e.listenerCount(t)}},function(e,t,n){"use strict";var r={};e.exports=r},function(e,t,n){"use strict";var r=n(82);e.exports=r.DEFAULT=new r({include:[n(118)],explicit:[n(809),n(808),n(807)]})},function(e,t,n){function r(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e]/;e.exports=i},function(e,t,n){"use strict";var r,i=n(25),o=n(243),a=/^[ \r\n\t\f]/,s=/<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/,u=n(251),l=u(function(e,t){if(e.namespaceURI!==o.svg||"innerHTML"in e)e.innerHTML=t;else{r=r||document.createElement("div"),r.innerHTML=""+t+"";for(var n=r.firstChild;n.firstChild;)e.appendChild(n.firstChild)}});if(i.canUseDOM){var c=document.createElement("div");c.innerHTML=" ",""===c.innerHTML&&(l=function(e,t){if(e.parentNode&&e.parentNode.replaceChild(e,e),a.test(t)||"<"===t[0]&&s.test(t)){e.innerHTML=String.fromCharCode(65279)+t;var n=e.firstChild;1===n.data.length?e.removeChild(n):n.deleteData(0,1)}else e.innerHTML=t}),c=null}e.exports=l},function(e,t,n){"use strict";function r(e){var t={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]="number"==typeof e[n]?e[n]:e[n].val);return t}t.__esModule=!0,t.default=r,e.exports=t.default},function(e,t,n){"use strict";e.exports=function(e,t){var n,r,i,o=-1,a=e.posMax,s=e.pos,u=e.isInLabel;if(e.isInLabel)return-1;if(e.labelUnmatchedScopes)return e.labelUnmatchedScopes--,-1;for(e.pos=t+1,e.isInLabel=!0,n=1;e.pos1&&void 0!==arguments[1])||arguments[1];return e=(0,s.normalizeArray)(e),{type:p,payload:{thing:e,shown:t}}}function a(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=(0,s.normalizeArray)(e),{type:c,payload:{thing:e,mode:t}}}Object.defineProperty(t,"__esModule",{value:!0}),t.SHOW=t.UPDATE_MODE=t.UPDATE_FILTER=t.UPDATE_LAYOUT=void 0,t.updateLayout=r,t.updateFilter=i,t.show=o,t.changeMode=a;var s=n(9),u=t.UPDATE_LAYOUT="layout_update_layout",l=t.UPDATE_FILTER="layout_update_filter",c=t.UPDATE_MODE="layout_update_mode",p=t.SHOW="layout_show"},function(e,t,n){"use strict";function r(e,t){return{type:u,payload:{selectedServerUrl:e,namespace:t}}}function i(e){var t=e.value,n=e.pathMethod;return{type:l,payload:{value:t,pathMethod:n}}}function o(e){var t=e.value,n=e.pathMethod;return{type:c,payload:{value:t,pathMethod:n}}}function a(e){var t=e.value,n=e.path,r=e.method;return{type:p,payload:{value:t,path:n,method:r}}}function s(e){var t=e.server,n=e.namespace,r=e.key,i=e.val;return{type:f,payload:{server:t,namespace:n,key:r,val:i}}}Object.defineProperty(t,"__esModule",{value:!0}),t.setSelectedServer=r,t.setRequestBodyValue=i,t.setRequestContentType=o,t.setResponseContentType=a,t.setServerVariableValue=s;var u=t.UPDATE_SELECTED_SERVER="oas3_set_servers",l=t.UPDATE_REQUEST_BODY_VALUE="oas3_set_request_body_value",c=t.UPDATE_REQUEST_CONTENT_TYPE="oas3_set_request_content_type",p=t.UPDATE_RESPONSE_CONTENT_TYPE="oas3_set_response_content_type",f=t.UPDATE_SERVER_VARIABLE_VALUE="oas3_set_server_variable_value"},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=h(e,t);if(n)return(0,s.default)(n,{declaration:!0,indent:"\t"})}Object.defineProperty(t,"__esModule",{value:!0}),t.memoizedSampleFromSchema=t.memoizedCreateXMLExample=t.sampleXmlFromSchema=t.inferSchema=t.sampleFromSchema=void 0,t.createXMLExample=i;var o=n(9),a=n(1204),s=r(a),u=n(973),l=r(u),c={string:function(){return"string"},string_email:function(){return"user@example.com"},"string_date-time":function(){return(new Date).toISOString()},number:function(){return 0},number_float:function(){return 0},integer:function(){return 0},boolean:function(e){return"boolean"!=typeof e.default||e.default}},p=function(e){e=(0,o.objectify)(e);var t=e,n=t.type,r=t.format,i=c[n+"_"+r]||c[n];return(0,o.isFunc)(i)?i(e):"Unknown Type: "+e.type},f=t.sampleFromSchema=function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=(0,o.objectify)(t),i=r.type,a=r.example,s=r.properties,u=r.additionalProperties,l=r.items,c=n.includeReadOnly,f=n.includeWriteOnly;if(void 0!==a)return a;if(!i)if(s)i="object";else{if(!l)return;i="array"}if("object"===i){var h=(0,o.objectify)(s),d={};for(var m in h)h[m].readOnly&&!c||h[m].writeOnly&&!f||(d[m]=e(h[m],n));if(!0===u)d.additionalProp1={};else if(u)for(var v=(0,o.objectify)(u),g=e(v,n),y=1;y<4;y++)d["additionalProp"+y]=g;return d}return"array"===i?[e(l,n)]:t.enum?t.default?t.default:(0,o.normalizeArray)(t.enum)[0]:"file"!==i?p(t):void 0},h=(t.inferSchema=function(e){return e.schema&&(e=e.schema),e.properties&&(e.type="object"),e},t.sampleXmlFromSchema=function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=(0,o.objectify)(t),i=r.type,a=r.properties,s=r.additionalProperties,u=r.items,l=r.example,c=n.includeReadOnly,f=n.includeWriteOnly,h=r.default,d={},m={},v=t.xml,g=v.name,y=v.prefix,_=v.namespace,b=r.enum,x=void 0,w=void 0;if(!i)if(a||s)i="object";else{if(!u)return;i="array"}if(g=g||"notagname",x=(y?y+":":"")+g,_){m[y?"xmlns:"+y:"xmlns"]=_}if("array"===i&&u){if(u.xml=u.xml||v||{},u.xml.name=u.xml.name||v.name,v.wrapped)return d[x]=[],Array.isArray(l)?l.forEach(function(t){u.example=t,d[x].push(e(u,n))}):Array.isArray(h)?h.forEach(function(t){u.default=t,d[x].push(e(u,n))}):d[x]=[e(u,n)],m&&d[x].push({_attr:m}),d;var k=[];return Array.isArray(l)?(l.forEach(function(t){u.example=t,k.push(e(u,n))}),k):Array.isArray(h)?(h.forEach(function(t){u.default=t,k.push(e(u,n))}),k):e(u,n)}if("object"===i){var E=(0,o.objectify)(a);d[x]=[],l=l||{};for(var S in E)if((!E[S].readOnly||c)&&(!E[S].writeOnly||f))if(E[S].xml=E[S].xml||{},E[S].xml.attribute){var C=Array.isArray(E[S].enum)&&E[S].enum[0],A=E[S].example,D=E[S].default;m[E[S].xml.name||S]=void 0!==A&&A||void 0!==l[S]&&l[S]||void 0!==D&&D||C||p(E[S])}else{E[S].xml.name=E[S].xml.name||S,E[S].example=void 0!==E[S].example?E[S].example:l[S];var O=e(E[S]);Array.isArray(O)?d[x]=d[x].concat(O):d[x].push(O)}return!0===s?d[x].push({additionalProp:"Anything can be here"}):s&&d[x].push({additionalProp:p(s)}),m&&d[x].push({_attr:m}),d}return w=void 0!==l?l:void 0!==h?h:Array.isArray(b)?b[0]:p(t),d[x]=m?[{_attr:m},w]:w,d});t.memoizedCreateXMLExample=(0,l.default)(i),t.memoizedSampleFromSchema=(0,l.default)(f)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){return e instanceof Error?{type:P,error:!0,payload:e}:"string"==typeof e?{type:P,payload:e.replace(/\t/g," ")||""}:{type:P,payload:""}}function o(e){return{type:H,payload:e}}function a(e){return{type:I,payload:e}}function s(e){if(!e||"object"!==(void 0===e?"undefined":(0,E.default)(e)))throw new Error("updateJson must only accept a simple JSON object");return{type:R,payload:e}}function u(e,t,n,r,i){return{type:j,payload:{path:e,value:r,paramName:t,paramIn:n,isXml:i}}}function l(e){return{type:W,payload:{pathMethod:e}}}function c(e,t){return{type:V,payload:{path:e,value:t,key:"consumes_value"}}}function p(e,t){return{type:V,payload:{path:e,value:t,key:"produces_value"}}}function f(e,t){return{type:z,payload:{path:e,method:t}}}function h(e,t){return{type:U,payload:{path:e,method:t}}}function d(e,t,n){return{type:G,payload:{scheme:e,path:t,method:n}}}Object.defineProperty(t,"__esModule",{value:!0}),t.execute=t.executeRequest=t.logRequest=t.setMutatedRequest=t.setRequest=t.setResponse=t.validateParams=t.formatIntoYaml=t.resolveSpec=t.parseToJson=t.SET_SCHEME=t.UPDATE_RESOLVED=t.UPDATE_OPERATION_VALUE=t.CLEAR_VALIDATE_PARAMS=t.CLEAR_REQUEST=t.CLEAR_RESPONSE=t.LOG_REQUEST=t.SET_MUTATED_REQUEST=t.SET_REQUEST=t.SET_RESPONSE=t.VALIDATE_PARAMS=t.UPDATE_PARAM=t.UPDATE_JSON=t.UPDATE_URL=t.UPDATE_SPEC=void 0;var m=n(20),v=r(m),g=n(97),y=r(g),_=n(36),b=r(_),x=n(47),w=r(x),k=n(48),E=r(k);t.updateSpec=i,t.updateResolved=o,t.updateUrl=a,t.updateJsonSpec=s,t.changeParam=u,t.clearValidateParams=l,t.changeConsumesValue=c,t.changeProducesValue=p,t.clearResponse=f,t.clearRequest=h,t.setScheme=d;var S=n(213),C=r(S),A=n(1194),D=r(A),O=n(266),M=r(O),T=n(9),P=t.UPDATE_SPEC="spec_update_spec",I=t.UPDATE_URL="spec_update_url",R=t.UPDATE_JSON="spec_update_json",j=t.UPDATE_PARAM="spec_update_param",F=t.VALIDATE_PARAMS="spec_validate_param",N=t.SET_RESPONSE="spec_set_response",B=t.SET_REQUEST="spec_set_request",L=t.SET_MUTATED_REQUEST="spec_set_mutated_request",q=t.LOG_REQUEST="spec_log_request",z=t.CLEAR_RESPONSE="spec_clear_response",U=t.CLEAR_REQUEST="spec_clear_request",W=t.CLEAR_VALIDATE_PARAMS="spec_clear_validate_param",V=t.UPDATE_OPERATION_VALUE="spec_update_operation_value",H=t.UPDATE_RESOLVED="spec_update_resolved",G=t.SET_SCHEME="set_scheme",J=(t.parseToJson=function(e){return function(t){var n=t.specActions,r=t.specSelectors,i=t.errActions,o=r.specStr,a=null;try{e=e||o(),i.clear({source:"parser"}),a=C.default.safeLoad(e)}catch(e){return console.error(e),i.newSpecErr({source:"parser",level:"error",message:e.reason,line:e.mark&&e.mark.line?e.mark.line+1:void 0})}return n.updateJsonSpec(a)}},t.resolveSpec=function(e,t){return function(n){var r=n.specActions,i=n.specSelectors,o=n.errActions,a=n.fn,s=a.fetch,u=a.resolve,l=a.AST,c=n.getConfigs,p=c(),f=p.modelPropertyMacro,h=p.parameterMacro,d=p.requestInterceptor,m=p.responseInterceptor;void 0===e&&(e=i.specJson()),void 0===t&&(t=i.url());var v=l.getLineNumberForPath,g=i.specStr();return u({fetch:s,spec:e,baseDoc:t,modelPropertyMacro:f,parameterMacro:h,requestInterceptor:d,responseInterceptor:m}).then(function(e){var t=e.spec,n=e.errors;if(o.clear({type:"thrown"}),n.length>0){var i=n.map(function(e){return console.error(e),e.line=e.fullPath?v(g,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",Object.defineProperty(e,"message",{enumerable:!0,value:e.message}),e});o.newThrownErrBatch(i)}return r.updateResolved(t)})}},t.formatIntoYaml=function(){return function(e){var t=e.specActions,n=e.specSelectors,r=n.specStr,i=t.updateSpec;try{var o=C.default.safeDump(C.default.safeLoad(r()),{indent:2});i(o)}catch(e){i(e)}}},t.validateParams=function(e,t){return{type:F,payload:{pathMethod:e,isOAS3:t}}},t.setResponse=function(e,t,n){return{payload:{path:e,method:t,res:n},type:N}},t.setRequest=function(e,t,n){return{payload:{path:e,method:t,req:n},type:B}},t.setMutatedRequest=function(e,t,n){return{payload:{path:e,method:t,req:n},type:L}},t.logRequest=function(e){return{payload:e,type:q}},t.executeRequest=function(e){return function(t){var n=t.fn,r=t.specActions,i=t.specSelectors,o=t.getConfigs,a=t.oas3Selectors,s=e.pathName,u=e.method,l=e.operation,c=o(),p=c.requestInterceptor,f=c.responseInterceptor,h=l.toJS();if(e.contextUrl=(0,D.default)(i.url()).toString(),h&&h.operationId?e.operationId=h.operationId:h&&s&&u&&(e.operationId=n.opId(h,s,u)),i.isOAS3()){var d=s+":"+u;e.server=a.selectedServer(d)||a.selectedServer();var m=a.serverVariables({server:e.server,namespace:d}).toJS(),v=a.serverVariables({server:e.server}).toJS();e.serverVariables=(0,w.default)(m).length?m:v,e.requestContentType=a.requestContentType(s,u),e.responseContentType=a.responseContentType(s,u)||"*/*";var g=a.requestBodyValue(s,u);(0,T.isJSONObject)(g)?e.requestBody=JSON.parse(g):e.requestBody=g}var y=(0,b.default)({},e);y=n.buildRequest(y),r.setRequest(e.pathName,e.method,y);var _=function(t){var n=p.apply(this,[t]),i=(0,b.default)({},n);return r.setMutatedRequest(e.pathName,e.method,i),n};e.requestInterceptor=_,e.responseInterceptor=f;var x=Date.now();return n.execute(e).then(function(t){t.duration=Date.now()-x,r.setResponse(e.pathName,e.method,t)}).catch(function(t){return r.setResponse(e.pathName,e.method,{error:!0,err:(0,M.default)(t)})})}},function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.path,n=e.method,r=(0,y.default)(e,["path","method"]);return function(e){var i=e.fn.fetch,o=e.specSelectors,a=e.specActions,s=o.spec().toJS(),u=o.operationScheme(t,n),l=o.contentTypeValues([t,n]).toJS(),c=l.requestContentType,p=l.responseContentType,f=/xml/i.test(c),h=o.parameterValues([t,n],f).toJS();return a.executeRequest((0,v.default)({fetch:i,spec:s,pathName:t,method:n,parameters:h,requestContentType:c,scheme:u,responseContentType:p},r))}});t.execute=J},function(e,t,n){"use strict";var r=n(9),i=n(1215);i.keys().forEach(function(t){if("./index.js"!==t){var n=i(t);e.exports[(0,r.pascalCaseFilename)(t)]=n.default?n.default:n}})},function(e,t,n){e.exports={default:n(598),__esModule:!0}},function(e,t,n){"use strict";function r(e){switch(e._type){case"document":case"block_quote":case"list":case"item":case"paragraph":case"heading":case"emph":case"strong":case"link":case"image":case"custom_inline":case"custom_block":return!0;default:return!1}}var i=function(e,t){this.current=e,this.entering=!0===t},o=function(){var e=this.current,t=this.entering;if(null===e)return null;var n=r(e);return t&&n?e._firstChild?(this.current=e._firstChild,this.entering=!0):this.entering=!1:e===this.root?this.current=null:null===e._next?(this.current=e._parent,this.entering=!1):(this.current=e._next,this.entering=!0),{entering:t,node:e}},a=function(e){return{current:e,root:e,entering:!0,next:o,resumeAt:i}},s=function(e,t){this._type=e,this._parent=null,this._firstChild=null,this._lastChild=null,this._prev=null,this._next=null,this._sourcepos=t,this._lastLineBlank=!1,this._open=!0,this._string_content=null,this._literal=null,this._listData={},this._info=null,this._destination=null,this._title=null,this._isFenced=!1,this._fenceChar=null,this._fenceLength=0,this._fenceOffset=null,this._level=null,this._onEnter=null,this._onExit=null},u=s.prototype;Object.defineProperty(u,"isContainer",{get:function(){return r(this)}}),Object.defineProperty(u,"type",{get:function(){return this._type}}),Object.defineProperty(u,"firstChild",{get:function(){return this._firstChild}}),Object.defineProperty(u,"lastChild",{get:function(){return this._lastChild}}),Object.defineProperty(u,"next",{get:function(){return this._next}}),Object.defineProperty(u,"prev",{get:function(){return this._prev}}),Object.defineProperty(u,"parent",{get:function(){return this._parent}}),Object.defineProperty(u,"sourcepos",{get:function(){return this._sourcepos}}),Object.defineProperty(u,"literal",{get:function(){return this._literal},set:function(e){this._literal=e}}),Object.defineProperty(u,"destination",{get:function(){return this._destination},set:function(e){this._destination=e}}),Object.defineProperty(u,"title",{get:function(){return this._title},set:function(e){this._title=e}}),Object.defineProperty(u,"info",{get:function(){return this._info},set:function(e){this._info=e}}),Object.defineProperty(u,"level",{get:function(){return this._level},set:function(e){this._level=e}}),Object.defineProperty(u,"listType",{get:function(){return this._listData.type},set:function(e){this._listData.type=e}}),Object.defineProperty(u,"listTight",{get:function(){return this._listData.tight},set:function(e){this._listData.tight=e}}),Object.defineProperty(u,"listStart",{get:function(){return this._listData.start},set:function(e){this._listData.start=e}}),Object.defineProperty(u,"listDelimiter",{get:function(){return this._listData.delimiter},set:function(e){this._listData.delimiter=e}}),Object.defineProperty(u,"onEnter",{get:function(){return this._onEnter},set:function(e){this._onEnter=e}}),Object.defineProperty(u,"onExit",{get:function(){return this._onExit},set:function(e){this._onExit=e}}),s.prototype.appendChild=function(e){e.unlink(),e._parent=this,this._lastChild?(this._lastChild._next=e,e._prev=this._lastChild,this._lastChild=e):(this._firstChild=e,this._lastChild=e)},s.prototype.prependChild=function(e){e.unlink(),e._parent=this,this._firstChild?(this._firstChild._prev=e,e._next=this._firstChild,this._firstChild=e):(this._firstChild=e,this._lastChild=e)},s.prototype.unlink=function(){this._prev?this._prev._next=this._next:this._parent&&(this._parent._firstChild=this._next),this._next?this._next._prev=this._prev:this._parent&&(this._parent._lastChild=this._prev),this._parent=null,this._next=null,this._prev=null},s.prototype.insertAfter=function(e){e.unlink(),e._next=this._next,e._next&&(e._next._prev=e),e._prev=this,this._next=e,e._parent=this._parent,e._next||(e._parent._lastChild=e)},s.prototype.insertBefore=function(e){e.unlink(),e._prev=this._prev,e._prev&&(e._prev._next=e),e._next=this,this._prev=e,e._parent=this._parent,e._prev||(e._parent._firstChild=e)},s.prototype.walker=function(){return new a(this)},e.exports=s},function(e,t){var n=Object.prototype.toString;e.exports=function(e){switch(n.call(e)){case"[object Date]":return"date";case"[object RegExp]":return"regexp";case"[object Arguments]":return"arguments";case"[object Array]":return"array";case"[object Error]":return"error"}return null===e?"null":void 0===e?"undefined":e!==e?"nan":e&&1===e.nodeType?"element":typeof(e=e.valueOf?e.valueOf():Object.prototype.valueOf.apply(e))}},function(e,t){e.exports=function(e,t,n,r){if(!(e instanceof t)||void 0!==r&&r in e)throw TypeError(n+": incorrect invocation!");return e}},function(e,t,n){var r=n(54),i=n(183),o=n(77),a=n(133),s=n(605);e.exports=function(e,t){var n=1==e,u=2==e,l=3==e,c=4==e,p=6==e,f=5==e||p,h=t||s;return function(t,s,d){for(var m,v,g=o(t),y=i(g),_=r(s,d,3),b=a(y.length),x=0,w=n?h(t,b):u?h(t,0):void 0;b>x;x++)if((f||x in y)&&(m=y[x],v=_(m,x,g),e))if(n)w[x]=v;else if(v)switch(e){case 3:return!0;case 5:return m;case 6:return x;case 2:w.push(m)}else if(c)return!1;return p?-1:l||c?c:w}}},function(e,t,n){var r=n(99),i=n(21)("toStringTag"),o="Arguments"==r(function(){return arguments}()),a=function(e,t){try{return e[t]}catch(e){}};e.exports=function(e){var t,n,s;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=a(t=Object(e),i))?n:o?r(t):"Object"==(s=r(t))&&"function"==typeof t.callee?"Arguments":s}},function(e,t){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,t,n){var r=n(30),i=n(24).document,o=r(i)&&r(i.createElement);e.exports=function(e){return o?i.createElement(e):{}}},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t,n){var r=n(99);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==r(e)?e.split(""):Object(e)}},function(e,t,n){"use strict";function r(e){var t,n;this.promise=new e(function(e,r){if(void 0!==t||void 0!==n)throw TypeError("Bad Promise constructor");t=e,n=r}),this.resolve=i(t),this.reject=i(n)}var i=n(98);e.exports.f=function(e){return new r(e)}},function(e,t,n){var r=n(38),i=n(614),o=n(182),a=n(189)("IE_PROTO"),s=function(){},u=function(){var e,t=n(181)("iframe"),r=o.length;for(t.style.display="none",n(333).appendChild(t),t.src="javascript:",e=t.contentWindow.document,e.open(),e.write("