This is an automated email from the ASF dual-hosted git repository. ilgrosso pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push: new b92248f160 [SYNCOPE-1700] Introducing ojson (#382) b92248f160 is described below commit b92248f160798e3f99c22ce80a5d54de32867d17 Author: Francesco Chicchiriccò <ilgro...@users.noreply.github.com> AuthorDate: Fri Oct 21 14:17:42 2022 +0200 [SYNCOPE-1700] Introducing ojson (#382) --- .github/workflows/oracle.yml | 4 + core/persistence-jpa-json/pom.xml | 122 +++++++++++- .../jpa/MyJPAJSONPersistenceContext.java | 2 +- ...ontext.java => OJPAJSONPersistenceContext.java} | 34 ++-- .../jpa/PGJPAJSONPersistenceContext.java | 2 +- .../persistence/jpa/dao/AbstractJPAJSONAnyDAO.java | 37 +++- .../core/persistence/jpa/dao/MyJPAJSONAnyDAO.java | 9 +- .../persistence/jpa/dao/MyJPAJSONAnySearchDAO.java | 20 +- .../persistence/jpa/dao/MyJPAJSONAuditConfDAO.java | 2 +- .../core/persistence/jpa/dao/OJPAJSONAnyDAO.java | 79 ++++++++ ...AnySearchDAO.java => OJPAJSONAnySearchDAO.java} | 209 ++++++++++----------- .../persistence/jpa/dao/OJPAJSONAuditConfDAO.java | 83 ++++++++ .../jpa/dao/OJPAJSONPlainSchemaDAO.java | 48 +++++ .../core/persistence/jpa/dao/PGJPAJSONAnyDAO.java | 16 +- .../persistence/jpa/dao/PGJPAJSONAnySearchDAO.java | 5 +- .../persistence/jpa/dao/PGJPAJSONAuditConfDAO.java | 2 +- .../jpa/entity/OJPAJSONEntityFactory.java | 30 +++ .../jpa/entity/anyobject/JPAJSONAnyObject.java | 2 - .../persistence/jpa/entity/group/JPAJSONGroup.java | 2 - .../jpa/entity/user/JPAJSONLinkedAccount.java | 2 - .../persistence/jpa/entity/user/JPAJSONUser.java | 2 - .../main/resources/META-INF/spring-orm-ojson.xml | 136 ++++++++++++++ .../src/main/resources/META-INF/spring.factories | 3 +- .../src/main/resources/audit/audit_ojson.sql | 24 +++ .../spring.factories => core-ojson.properties} | 20 +- .../src/main/resources/myjson/views.xml | 12 +- .../src/main/resources/ojson/indexes.xml | 59 ++++++ .../src/main/resources/{myjson => ojson}/views.xml | 84 +++++---- .../src/main/resources/persistence-enhance.xml | 2 +- .../jpa/JPAJSONTestContextCustomizer.java | 34 ++-- .../resources/core-ojson-test.properties} | 12 +- .../src/test/resources/domains/MasterContent.xml | 5 +- .../core/persistence/jpa/dao/JPAAnySearchDAO.java | 5 + .../core/persistence/jpa/inner/UserTest.java | 4 +- fit/core-reference/pom.xml | 114 ++++++++++- .../fit/core/reference/ITImplementationLookup.java | 10 + .../src/main/resources/core-ojson.properties | 20 +- .../apache/syncope/fit/core/AnyObjectITCase.java | 20 +- .../org/apache/syncope/fit/core/AuditITCase.java | 3 +- pom.xml | 1 + .../getting-started/systemRequirements.adoc | 4 +- .../reference-guide/configuration/dbms.adoc | 55 +++++- 42 files changed, 1076 insertions(+), 263 deletions(-) diff --git a/.github/workflows/oracle.yml b/.github/workflows/oracle.yml index 2253bec62b..e1c0bd4107 100644 --- a/.github/workflows/oracle.yml +++ b/.github/workflows/oracle.yml @@ -44,5 +44,9 @@ jobs: restore-keys: ${{ runner.os }}-m2 - name: Build run: mvn -U -T 1C -P 'skipTests,all' + - name: 'Unit Tests: Oracle JPA JSON' + run: mvn -f core/persistence-jpa-json/pom.xml -P ojson -Dinvoker.streamLogs=true -Dmodernizer.skip=true -Dianal.phase=none -Drat.skip=true -Dcheckstyle.skip=true -Djacoco.skip=true - name: 'Integration Tests: Oracle' run: mvn -f fit/core-reference/pom.xml -P oracle-it -Dinvoker.streamLogs=true -Dmodernizer.skip=true -Drat.skip=true -Dcheckstyle.skip=true -Djacoco.skip=true + - name: 'Integration Tests: Oracle JPA JSON' + run: mvn -f fit/core-reference/pom.xml -P ojson-it -Dinvoker.streamLogs=true -Dmodernizer.skip=true -Drat.skip=true -Dcheckstyle.skip=true -Djacoco.skip=true diff --git a/core/persistence-jpa-json/pom.xml b/core/persistence-jpa-json/pom.xml index 682630b722..71350950c1 100644 --- a/core/persistence-jpa-json/pom.xml +++ b/core/persistence-jpa-json/pom.xml @@ -34,6 +34,7 @@ under the License. <packaging>jar</packaging> <properties> + <orm>pgjsonb</orm> <rootpom.basedir>${basedir}/../..</rootpom.basedir> </properties> @@ -101,7 +102,7 @@ under the License. </dependency> </dependencies> <configuration> - <persistenceXmlFile>${project.basedir}/src/main/resources/persistence-enhance.xml</persistenceXmlFile> + <persistenceXmlFile>${project.build.directory}/classes/persistence-enhance.xml</persistenceXmlFile> <includes>org/apache/syncope/core/persistence/jpa/entity/**/*.class</includes> <connectionDriverName>org.springframework.jdbc.datasource.DriverManagerDataSource</connectionDriverName> <connectionProperties> @@ -187,9 +188,15 @@ under the License. </profile> <profile> - <id>schemagen</id> + <id>openjpa</id> <properties> + <!-- possible values: sql | schema --> + <action>sql</action> + + <!-- possible values: pgjsonb | myjson | ojson --> + <orm>ojson</orm> + <skipTests>true</skipTests> </properties> @@ -206,7 +213,7 @@ under the License. <id>schemagen</id> <phase>process-classes</phase> <goals> - <goal>schema</goal> + <goal>${action}</goal> </goals> </execution> </executions> @@ -441,5 +448,114 @@ under the License. </testResources> </build> </profile> + + <profile> + <id>ojson</id> + + <dependencies> + <dependency> + <groupId>com.oracle.database.jdbc</groupId> + <artifactId>ojdbc11</artifactId> + <version>${jdbc.oracle.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <defaultGoal>clean verify</defaultGoal> + + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <id>add-test-source</id> + <phase>generate-test-sources</phase> + <goals> + <goal>add-test-source</goal> + </goals> + <configuration> + <sources> + <source>${basedir}/../persistence-jpa/src/test/java</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-failsafe-plugin</artifactId> + <configuration> + <includes> + <include>**/*Test.java</include> + </includes> + <excludedGroups>multitenancy,plainAttrTable</excludedGroups> + <systemProperties> + <profileId>${project.activeProfiles[0].id}</profileId> + <CORE_PROPERTIES>classpath:core-ojson.properties,classpath:core-ojson-test.properties</CORE_PROPERTIES> + <DB_CONTAINER_IP>${docker.container.oracle.ip}</DB_CONTAINER_IP> + </systemProperties> + </configuration> + </plugin> + + <plugin> + <groupId>io.fabric8</groupId> + <artifactId>docker-maven-plugin</artifactId> + <configuration> + <images> + <image> + <alias>oracle</alias> + <name>gvenzl/oracle-xe:21-slim</name> + <run> + <env> + <ORACLE_PASSWORD>password</ORACLE_PASSWORD> + <APP_USER>syncope</APP_USER> + <APP_USER_PASSWORD>syncope</APP_USER_PASSWORD> + </env> + <wait> + <log>DATABASE IS READY TO USE</log> + <time>120000</time> + </wait> + </run> + </image> + </images> + </configuration> + <executions> + <execution> + <id>start-oracle</id> + <phase>pre-integration-test</phase> + <goals> + <goal>start</goal> + </goals> + </execution> + <execution> + <id>stop-oracle</id> + <phase>post-integration-test</phase> + <goals> + <goal>stop</goal> + <goal>remove</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + + <testResources> + <testResource> + <directory>src/test/resources</directory> + <filtering>true</filtering> + </testResource> + </testResources> + </build> + </profile> </profiles> </project> diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/MyJPAJSONPersistenceContext.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/MyJPAJSONPersistenceContext.java index b638bb1051..71805a969a 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/MyJPAJSONPersistenceContext.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/MyJPAJSONPersistenceContext.java @@ -42,7 +42,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Lazy; -@ConditionalOnExpression("#{!('${provisioning.quartz.delegate}' matches '.*PostgreSQLDelegate.*')}") +@ConditionalOnExpression("#{'${provisioning.quartz.sql}' matches '.*mysql.*'}") public class MyJPAJSONPersistenceContext extends JPAJSONPersistenceContext { @ConditionalOnMissingBean(name = "myJPAJSONEntityFactory") diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/OJPAJSONPersistenceContext.java similarity index 74% copy from core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java copy to core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/OJPAJSONPersistenceContext.java index 551b2c859d..4b945e9c72 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/OJPAJSONPersistenceContext.java @@ -32,32 +32,32 @@ import org.apache.syncope.core.persistence.api.dao.RealmDAO; import org.apache.syncope.core.persistence.api.dao.UserDAO; import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; import org.apache.syncope.core.persistence.api.entity.EntityFactory; -import org.apache.syncope.core.persistence.jpa.dao.PGJPAJSONAnyDAO; -import org.apache.syncope.core.persistence.jpa.dao.PGJPAJSONAnySearchDAO; -import org.apache.syncope.core.persistence.jpa.dao.PGJPAJSONAuditConfDAO; -import org.apache.syncope.core.persistence.jpa.dao.PGJPAJSONPlainSchemaDAO; -import org.apache.syncope.core.persistence.jpa.entity.PGJPAJSONEntityFactory; +import org.apache.syncope.core.persistence.jpa.dao.OJPAJSONAnyDAO; +import org.apache.syncope.core.persistence.jpa.dao.OJPAJSONAnySearchDAO; +import org.apache.syncope.core.persistence.jpa.dao.OJPAJSONAuditConfDAO; +import org.apache.syncope.core.persistence.jpa.dao.OJPAJSONPlainSchemaDAO; +import org.apache.syncope.core.persistence.jpa.entity.OJPAJSONEntityFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Lazy; -@ConditionalOnExpression("#{'${provisioning.quartz.delegate}' matches '.*PostgreSQLDelegate.*'}") -public class PGJPAJSONPersistenceContext extends JPAJSONPersistenceContext { +@ConditionalOnExpression("#{'${provisioning.quartz.sql}' matches '.*oracle.*'}") +public class OJPAJSONPersistenceContext extends JPAJSONPersistenceContext { - @ConditionalOnMissingBean(name = "pgJPAJSONEntityFactory") + @ConditionalOnMissingBean(name = "oJPAJSONEntityFactory") @Bean public EntityFactory entityFactory() { - return new PGJPAJSONEntityFactory(); + return new OJPAJSONEntityFactory(); } - @ConditionalOnMissingBean(name = "pgJPAJSONAnyDAO") + @ConditionalOnMissingBean(name = "oJPAJSONAnyDAO") @Bean public JPAJSONAnyDAO anyDAO(final @Lazy PlainSchemaDAO plainSchemaDAO) { - return new PGJPAJSONAnyDAO(plainSchemaDAO); + return new OJPAJSONAnyDAO(plainSchemaDAO); } - @ConditionalOnMissingBean(name = "pgJPAJSONAnySearchDAO") + @ConditionalOnMissingBean(name = "oJPAJSONAnySearchDAO") @Bean public AnySearchDAO anySearchDAO( final @Lazy RealmDAO realmDAO, @@ -70,7 +70,7 @@ public class PGJPAJSONPersistenceContext extends JPAJSONPersistenceContext { final AnyUtilsFactory anyUtilsFactory, final PlainAttrValidationManager validator) { - return new PGJPAJSONAnySearchDAO( + return new OJPAJSONAnySearchDAO( realmDAO, dynRealmDAO, userDAO, @@ -82,19 +82,19 @@ public class PGJPAJSONPersistenceContext extends JPAJSONPersistenceContext { validator); } - @ConditionalOnMissingBean(name = "pgJPAJSONAuditConfDAO") + @ConditionalOnMissingBean(name = "oJPAJSONAuditConfDAO") @Bean public AuditConfDAO auditConfDAO() { - return new PGJPAJSONAuditConfDAO(); + return new OJPAJSONAuditConfDAO(); } - @ConditionalOnMissingBean(name = "pgJPAJSONPlainSchemaDAO") + @ConditionalOnMissingBean(name = "oJPAJSONPlainSchemaDAO") @Bean public PlainSchemaDAO plainSchemaDAO( final AnyUtilsFactory anyUtilsFactory, final @Lazy PlainAttrDAO plainAttrDAO, final @Lazy ExternalResourceDAO resourceDAO) { - return new PGJPAJSONPlainSchemaDAO(anyUtilsFactory, plainAttrDAO, resourceDAO); + return new OJPAJSONPlainSchemaDAO(anyUtilsFactory, plainAttrDAO, resourceDAO); } } diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java index 551b2c859d..1de2c8d9e8 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java @@ -42,7 +42,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Lazy; -@ConditionalOnExpression("#{'${provisioning.quartz.delegate}' matches '.*PostgreSQLDelegate.*'}") +@ConditionalOnExpression("#{'${provisioning.quartz.sql}' matches '.*postgres.*'}") public class PGJPAJSONPersistenceContext extends JPAJSONPersistenceContext { @ConditionalOnMissingBean(name = "pgJPAJSONEntityFactory") diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnyDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnyDAO.java index 827729c1dc..1101148d7c 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnyDAO.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnyDAO.java @@ -34,6 +34,7 @@ import org.apache.commons.jexl3.parser.ParserConstants; import org.apache.commons.jexl3.parser.Token; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; +import org.apache.syncope.common.lib.types.AnyTypeKind; import org.apache.syncope.common.lib.types.AttrSchemaType; import org.apache.syncope.core.persistence.api.dao.DuplicateException; import org.apache.syncope.core.persistence.api.dao.JPAJSONAnyDAO; @@ -58,13 +59,15 @@ abstract class AbstractJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> impleme this.plainSchemaDAO = plainSchemaDAO; } - protected abstract String queryBegin(String table); + protected String view(final String table) { + return StringUtils.containsIgnoreCase(table, AnyTypeKind.USER.name()) + ? "user_search" + : StringUtils.containsIgnoreCase(table, AnyTypeKind.GROUP.name()) + ? "group_search" + : "anyObject_search"; + } - protected abstract String attrValueMatch( - AnyUtils anyUtils, - PlainSchema schema, - PlainAttrValue attrValue, - boolean ignoreCaseMatch); + protected abstract String queryBegin(String table); protected Pair<String, Boolean> schemaInfo(final AttrSchemaType schemaType, final boolean ignoreCaseMatch) { String key; @@ -99,6 +102,20 @@ abstract class AbstractJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> impleme return Pair.of(key, lower); } + protected abstract String attrValueMatch( + AnyUtils anyUtils, + PlainSchema schema, + PlainAttrValue attrValue, + boolean ignoreCaseMatch); + + protected Object getAttrValue( + final PlainSchema schema, + final PlainAttrValue attrValue, + final boolean ignoreCaseMatch) { + + return attrValue.getValue(); + } + protected <A extends Any<?>> List<A> buildResult(final AnyUtils anyUtils, final List<Object> queryResult) { List<A> result = new ArrayList<>(); queryResult.forEach(anyKey -> { @@ -131,7 +148,7 @@ abstract class AbstractJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> impleme queryBegin(table) + "WHERE " + attrValueMatch(anyUtils, schema, attrValue, ignoreCaseMatch)); query.setParameter(1, schema.getKey()); - query.setParameter(2, attrValue.getValue()); + query.setParameter(2, getAttrValue(schema, attrValue, ignoreCaseMatch)); return buildResult(anyUtils, query.getResultList()); } @@ -167,8 +184,8 @@ abstract class AbstractJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> impleme * @param literals literals/tokens * @return split value */ - private static List<String> split(final String attrValue, final List<String> literals) { - final List<String> attrValues = new ArrayList<>(); + protected List<String> split(final String attrValue, final List<String> literals) { + List<String> attrValues = new ArrayList<>(); if (literals.isEmpty()) { attrValues.add(attrValue); @@ -303,7 +320,7 @@ abstract class AbstractJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> impleme List<Object> queryParams = new ArrayList<>(); queryParams.add(schema.getKey()); - queryParams.add(attrValues.get(i)); + queryParams.add(getAttrValue(schema, attrValue, ignoreCaseMatch)); clauses.put(bld.toString(), queryParams); } diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnyDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnyDAO.java index c26f7ea307..06ad3692c1 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnyDAO.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnyDAO.java @@ -19,9 +19,7 @@ package org.apache.syncope.core.persistence.jpa.dao; import java.util.List; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; -import org.apache.syncope.common.lib.types.AnyTypeKind; import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO; import org.apache.syncope.core.persistence.api.entity.AnyUtils; import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr; @@ -39,12 +37,7 @@ public class MyJPAJSONAnyDAO extends AbstractJPAJSONAnyDAO { @Override protected String queryBegin(final String table) { - String view = StringUtils.containsIgnoreCase(table, AnyTypeKind.USER.name()) - ? "user_search" - : StringUtils.containsIgnoreCase(table, AnyTypeKind.GROUP.name()) - ? "group_search" - : "anyObject_search"; - return "SELECT DISTINCT id FROM " + view + ' '; + return "SELECT DISTINCT id FROM " + view(table) + ' '; } @Override diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java index a76fe02804..40f4c1cf91 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java @@ -86,7 +86,9 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO { StringBuilder nullAttrWhere = new StringBuilder(); if (svs.nonMandatorySchemas || obs.nonMandatorySchemas) { - where.append(", (SELECT * FROM ").append(searchView.name); + where.append(", (SELECT ").append(SELECT_COLS_FROM_VIEW).append(",plainSchema," + + "binaryValue,booleanValue,dateValue,doubleValue,longValue,stringValue,attrUniqueValue " + + "FROM ").append(searchView.name); searchViewAddedToWhere = true; attrs.forEach(field -> { @@ -97,22 +99,20 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO { } attrWhere.append("JSON_CONTAINS(plainAttrs, '[{\"schema\":\"").append(field).append("\"}]')"); - nullAttrWhere.append(" UNION SELECT DISTINCT any_id,").append(svs.table().alias).append(".*, "). - append('"').append(field).append('"').append(" AS plainSchema, "). + nullAttrWhere.append(" UNION SELECT DISTINCT ").append(SELECT_COLS_FROM_VIEW).append(", "). + append("'").append(field).append("'").append(" AS plainSchema, "). append("null AS binaryValue, "). append("null AS booleanValue, "). append("null AS dateValue, "). append("null AS doubleValue, "). append("null AS longValue, "). append("null AS stringValue, "). - append("null AS attrUniqueValue"). - append(" FROM ").append(svs.table().name).append(' ').append(svs.table().alias). - append(", ").append(svs.field().name). - append(" WHERE any_id=").append(svs.table().alias).append(".id"). - append(" AND any_id NOT IN "). - append("(SELECT distinct any_id FROM "). + append("null AS attrUniqueValue "). + append("FROM ").append(svs.field().name). + append(" WHERE any_id NOT IN "). + append("(SELECT DISTINCT any_id FROM "). append(svs.field().name). - append(" WHERE ").append(svs.table().alias).append(".id=any_id AND "). + append(" WHERE "). append("JSON_CONTAINS(plainAttrs, '[{\"schema\":\"").append(field).append("\"}]'))"); }); where.append(attrWhere).append(nullAttrWhere).append(')'); diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAuditConfDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAuditConfDAO.java index 4b64c8c5f1..453fc152e1 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAuditConfDAO.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAuditConfDAO.java @@ -25,7 +25,7 @@ import org.apache.syncope.core.provisioning.api.serialization.POJOHelper; public class MyJPAJSONAuditConfDAO extends AbstractJPAJSONLoggerDAO { - private static class MyMessageCriteriaBuilder extends JSONMessageCriteriaBuilder { + protected static class MyMessageCriteriaBuilder extends JSONMessageCriteriaBuilder { @Override protected String doBuild(final List<ObjectNode> containers) { diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAnyDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAnyDAO.java new file mode 100644 index 0000000000..184860caa5 --- /dev/null +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAnyDAO.java @@ -0,0 +1,79 @@ +/* + * 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. + */ +package org.apache.syncope.core.persistence.jpa.dao; + +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.syncope.common.lib.types.AttrSchemaType; +import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO; +import org.apache.syncope.core.persistence.api.entity.AnyUtils; +import org.apache.syncope.core.persistence.api.entity.PlainAttrValue; +import org.apache.syncope.core.persistence.api.entity.PlainSchema; + +public class OJPAJSONAnyDAO extends AbstractJPAJSONAnyDAO { + + public OJPAJSONAnyDAO(final PlainSchemaDAO plainSchemaDAO) { + super(plainSchemaDAO); + } + + @Override + protected String queryBegin(final String table) { + return "SELECT DISTINCT id FROM " + view(table) + ' '; + } + + @Override + protected Object getAttrValue( + final PlainSchema schema, + final PlainAttrValue attrValue, + final boolean ignoreCaseMatch) { + + return schema.getType() == AttrSchemaType.Boolean + ? BooleanUtils.toStringTrueFalse(attrValue.getBooleanValue()) + : schema.getType() == AttrSchemaType.String && ignoreCaseMatch + ? StringUtils.lowerCase(attrValue.getStringValue()) + : attrValue.getValue(); + } + + @Override + protected String attrValueMatch( + final AnyUtils anyUtils, + final PlainSchema schema, + final PlainAttrValue attrValue, + final boolean ignoreCaseMatch) { + + StringBuilder query = new StringBuilder("plainSchema = ? AND "); + + Pair<String, Boolean> schemaInfo = schemaInfo(schema.getType(), ignoreCaseMatch); + query.append(schemaInfo.getRight() ? "LOWER(" : ""); + + if (schema.isUniqueConstraint()) { + query.append("u").append(schemaInfo.getLeft()); + } else { + query.append("JSON_VALUE(").append(schemaInfo.getLeft()).append(", '$[*]')"); + } + + query.append(schemaInfo.getRight() ? ")" : ""). + append(" = "). + append(schemaInfo.getRight() ? "LOWER(" : ""). + append('?').append(schemaInfo.getRight() ? ")" : ""); + + return query.toString(); + } +} diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAnySearchDAO.java similarity index 60% copy from core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java copy to core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAnySearchDAO.java index a76fe02804..ad4aaa9434 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAnySearchDAO.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.syncope.common.lib.types.AttrSchemaType; import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager; @@ -38,16 +39,12 @@ import org.apache.syncope.core.persistence.api.dao.search.OrderByClause; import org.apache.syncope.core.persistence.api.entity.AnyUtils; import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; import org.apache.syncope.core.persistence.api.entity.EntityFactory; -import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr; -import org.apache.syncope.core.persistence.api.entity.PlainAttr; -import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue; import org.apache.syncope.core.persistence.api.entity.PlainAttrValue; import org.apache.syncope.core.persistence.api.entity.PlainSchema; -import org.apache.syncope.core.provisioning.api.serialization.POJOHelper; -public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO { +public class OJPAJSONAnySearchDAO extends JPAAnySearchDAO { - public MyJPAJSONAnySearchDAO( + public OJPAJSONAnySearchDAO( final RealmDAO realmDAO, final DynRealmDAO dynRealmDAO, final UserDAO userDAO, @@ -86,7 +83,10 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO { StringBuilder nullAttrWhere = new StringBuilder(); if (svs.nonMandatorySchemas || obs.nonMandatorySchemas) { - where.append(", (SELECT * FROM ").append(searchView.name); + where.append(", (SELECT ").append(SELECT_COLS_FROM_VIEW).append(",plainSchema," + + "ubinaryValue,ubooleanValue,udateValue,udoubleValue,ulongValue,ustringValue," + + "binaryValue,booleanValue,dateValue,doubleValue,longValue,stringValue FROM "). + append(searchView.name); searchViewAddedToWhere = true; attrs.forEach(field -> { @@ -95,25 +95,28 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO { } else { attrWhere.append(" OR "); } - attrWhere.append("JSON_CONTAINS(plainAttrs, '[{\"schema\":\"").append(field).append("\"}]')"); - - nullAttrWhere.append(" UNION SELECT DISTINCT any_id,").append(svs.table().alias).append(".*, "). - append('"').append(field).append('"').append(" AS plainSchema, "). + attrWhere.append("JSON_EXISTS(plainAttrs, '$[*]?(@.schema == \"").append(field).append("\")')"); + + nullAttrWhere.append(" UNION SELECT DISTINCT ").append(SELECT_COLS_FROM_VIEW).append(","). + append("'").append(field).append("'").append(" AS plainSchema, "). + append("null AS ubinaryValue, "). + append("null AS ubooleanValue, "). + append("null AS udateValue, "). + append("null AS udoubleValue, "). + append("null AS ulongValue, "). + append("null AS ustringValue, "). append("null AS binaryValue, "). append("null AS booleanValue, "). append("null AS dateValue, "). append("null AS doubleValue, "). append("null AS longValue, "). - append("null AS stringValue, "). - append("null AS attrUniqueValue"). - append(" FROM ").append(svs.table().name).append(' ').append(svs.table().alias). - append(", ").append(svs.field().name). - append(" WHERE any_id=").append(svs.table().alias).append(".id"). - append(" AND any_id NOT IN "). - append("(SELECT distinct any_id FROM "). + append("null AS stringValue "). + append("FROM ").append(svs.field().name). + append(" WHERE any_id NOT IN "). + append("(SELECT DISTINCT any_id FROM "). append(svs.field().name). - append(" WHERE ").append(svs.table().alias).append(".id=any_id AND "). - append("JSON_CONTAINS(plainAttrs, '[{\"schema\":\"").append(field).append("\"}]'))"); + append(" WHERE "). + append("JSON_EXISTS(plainAttrs, '$[*]?(@.schema == \"").append(field).append("\")'))"); }); where.append(attrWhere).append(nullAttrWhere).append(')'); } @@ -141,7 +144,7 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO { obs.views.add(svs.field()); item.select = svs.field().alias + '.' - + (schema.isUniqueConstraint() ? "attrUniqueValue" : key(schema.getType())) + + (schema.isUniqueConstraint() ? "u" : "") + key(schema.getType()) + " AS " + fieldName; item.where = "plainSchema = '" + fieldName + '\''; item.orderBy = fieldName + ' ' + clause.getDirection().name(); @@ -167,90 +170,80 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO { fillAttrQuery(anyUtils, query, attrValue, schema, cond, false, parameters, svs); query.append(')'); } else { - if (!not && cond.getType() == AttrCond.Type.EQ) { - PlainAttr<?> container = anyUtils.newPlainAttr(); - container.setSchema(schema); - if (attrValue instanceof PlainAttrUniqueValue) { - container.setUniqueValue((PlainAttrUniqueValue) attrValue); - } else { - ((JSONPlainAttr) container).add(attrValue); - } - - query.append("JSON_CONTAINS(plainAttrs, '"). - append(POJOHelper.serialize(List.of(container)).replace("'", "''")). - append("')"); + String key = key(schema.getType()); + + String value = Optional.ofNullable(attrValue.getDateValue()). + map(DateTimeFormatter.ISO_OFFSET_DATE_TIME::format). + orElseGet(() -> schema.getType() == AttrSchemaType.Boolean + ? BooleanUtils.toStringTrueFalse(attrValue.getBooleanValue()) + : cond.getExpression()); + + boolean lower = (schema.getType() == AttrSchemaType.String || schema.getType() == AttrSchemaType.Enum) + && (cond.getType() == AttrCond.Type.IEQ || cond.getType() == AttrCond.Type.ILIKE); + + query.append("plainSchema=?").append(setParameter(parameters, cond.getSchema())). + append(" AND "). + append(lower ? "LOWER(" : ""); + if (schema.isUniqueConstraint()) { + query.append("u").append(key); } else { - String key = key(schema.getType()); - - String value = Optional.ofNullable(attrValue.getDateValue()). - map(DateTimeFormatter.ISO_OFFSET_DATE_TIME::format). - orElse(cond.getExpression()); - - boolean lower = (schema.getType() == AttrSchemaType.String || schema.getType() == AttrSchemaType.Enum) - && (cond.getType() == AttrCond.Type.IEQ || cond.getType() == AttrCond.Type.ILIKE); - - query.append("plainSchema=?").append(setParameter(parameters, cond.getSchema())). - append(" AND "). - append(lower ? "LOWER(" : ""). - append(schema.isUniqueConstraint() - ? "attrUniqueValue ->> '$." + key + '\'' - : key). - append(lower ? ')' : ""); - - switch (cond.getType()) { - case LIKE: - case ILIKE: - if (not) { - query.append("NOT "); - } - query.append(" LIKE "); - break; - - case GE: - if (not) { - query.append('<'); - } else { - query.append(">="); - } - break; - - case GT: - if (not) { - query.append("<="); - } else { - query.append('>'); - } - break; - - case LE: - if (not) { - query.append('>'); - } else { - query.append("<="); - } - break; - - case LT: - if (not) { - query.append(">="); - } else { - query.append('<'); - } - break; - - case EQ: - case IEQ: - default: - if (not) { - query.append('!'); - } - query.append('='); - } - - query.append(lower ? "LOWER(" : ""). - append('?').append(setParameter(parameters, value)). - append(lower ? ")" : ""); + query.append("JSON_VALUE(").append(key).append(", '$[*]')"); } + query.append(lower ? ')' : ""); + + switch (cond.getType()) { + case LIKE: + case ILIKE: + if (not) { + query.append("NOT "); + } + query.append(" LIKE "); + break; + + case GE: + if (not) { + query.append('<'); + } else { + query.append(">="); + } + break; + + case GT: + if (not) { + query.append("<="); + } else { + query.append('>'); + } + break; + + case LE: + if (not) { + query.append('>'); + } else { + query.append("<="); + } + break; + + case LT: + if (not) { + query.append(">="); + } else { + query.append('<'); + } + break; + + case EQ: + case IEQ: + default: + if (not) { + query.append('!'); + } + query.append('='); + } + + query.append(lower ? "LOWER(" : ""). + append('?').append(setParameter(parameters, value)). + append(lower ? ")" : ""); } } @@ -276,15 +269,13 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO { new StringBuilder("SELECT DISTINCT any_id FROM ").append(svs.field().name).append(" WHERE "); switch (cond.getType()) { case ISNOTNULL: - query.append("JSON_SEARCH(plainAttrs, 'one', '"). - append(checked.getLeft().getKey()). - append("', NULL, '$[*].schema') IS NOT NULL"); + query.append("JSON_EXISTS(plainAttrs, '$[*]?(@.schema == \""). + append(checked.getLeft().getKey()).append("\")')"); break; case ISNULL: - query.append("JSON_SEARCH(plainAttrs, 'one', '"). - append(checked.getLeft().getKey()). - append("', NULL, '$[*].schema') IS NULL"); + query.append("NOT JSON_EXISTS(plainAttrs, '$[*]?(@.schema == \""). + append(checked.getLeft().getKey()).append("\")')"); break; default: diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAuditConfDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAuditConfDAO.java new file mode 100644 index 0000000000..6afc9a9ed8 --- /dev/null +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAuditConfDAO.java @@ -0,0 +1,83 @@ +/* + * 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. + */ +package org.apache.syncope.core.persistence.jpa.dao; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +public class OJPAJSONAuditConfDAO extends AbstractJPAJSONLoggerDAO { + + protected static class OMessageCriteriaBuilder extends JSONMessageCriteriaBuilder { + + protected Optional<String> jsonExprItem(final JsonNode logger, final String field) { + return logger.has(field) + ? Optional.of("@.logger." + field + " == \"" + logger.get(field).asText() + "\"") + : Optional.empty(); + } + + @Override + protected String doBuild(final List<ObjectNode> containers) { + if (entityKey != null) { + query.append('('). + append("JSON_VALUE(").append(AUDIT_ENTRY_MESSAGE_COLUMN). + append(", '$.before' RETURNING VARCHAR2(32767)) LIKE '%"). + append(entityKey).append("%' OR "). + append("JSON_VALUE(").append(AUDIT_ENTRY_MESSAGE_COLUMN). + append(", '$.input' RETURNING VARCHAR2(32767)) LIKE '%"). + append(entityKey).append("%' OR "). + append("JSON_VALUE(").append(AUDIT_ENTRY_MESSAGE_COLUMN). + append(", '$.output' RETURNING VARCHAR2(32767)) LIKE '%"). + append(entityKey).append("%')"); + } + + if (!containers.isEmpty()) { + if (entityKey != null) { + query.append(" AND ("); + } + query.append(containers.stream().filter(container -> container.has("logger")).map(container -> { + JsonNode logger = container.get("logger"); + + List<String> clauses = new ArrayList<>(); + jsonExprItem(logger, "type").ifPresent(clauses::add); + jsonExprItem(logger, "category").ifPresent(clauses::add); + jsonExprItem(logger, "subcategory").ifPresent(clauses::add); + jsonExprItem(logger, "result").ifPresent(clauses::add); + jsonExprItem(logger, "event").ifPresent(clauses::add); + + return "JSON_EXISTS(MESSAGE, '$[*]?(" + String.join(" && ", clauses) + ")')"; + }).filter(Objects::nonNull).collect(Collectors.joining(" OR "))); + if (entityKey != null) { + query.append(')'); + } + } + + return query.toString(); + } + } + + @Override + protected MessageCriteriaBuilder messageCriteriaBuilder(final String entityKey) { + return new OMessageCriteriaBuilder().entityKey(entityKey); + } +} diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONPlainSchemaDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONPlainSchemaDAO.java new file mode 100644 index 0000000000..b317243fd4 --- /dev/null +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONPlainSchemaDAO.java @@ -0,0 +1,48 @@ +/* + * 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. + */ +package org.apache.syncope.core.persistence.jpa.dao; + +import javax.persistence.Query; +import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO; +import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO; +import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; +import org.apache.syncope.core.persistence.api.entity.PlainAttr; +import org.apache.syncope.core.persistence.api.entity.PlainSchema; + +public class OJPAJSONPlainSchemaDAO extends AbstractJPAJSONPlainSchemaDAO { + + public OJPAJSONPlainSchemaDAO( + final AnyUtilsFactory anyUtilsFactory, + final PlainAttrDAO plainAttrDAO, + final ExternalResourceDAO resourceDAO) { + + super(anyUtilsFactory, plainAttrDAO, resourceDAO); + } + + @Override + public <T extends PlainAttr<?>> boolean hasAttrs(final PlainSchema schema, final Class<T> reference) { + Query query = entityManager().createNativeQuery( + "SELECT COUNT(id) FROM " + + new SearchSupport(getAnyTypeKind(reference)).field().name + + " WHERE plainSchema = ?"); + query.setParameter(1, schema.getKey()); + + return ((Number) query.getSingleResult()).intValue() > 0; + } +} diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnyDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnyDAO.java index d356a8783c..2bc9ad4e2a 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnyDAO.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnyDAO.java @@ -61,15 +61,15 @@ public class PGJPAJSONAnyDAO extends AbstractJPAJSONAnyDAO { + (schemaInfo.getRight() ? "LOWER(" : "") + '?' + (schemaInfo.getRight() ? ")" : ""); + } + + PlainAttr<?> container = anyUtils.newPlainAttr(); + container.setSchema(schema); + if (attrValue instanceof PlainAttrUniqueValue) { + container.setUniqueValue((PlainAttrUniqueValue) attrValue); } else { - PlainAttr<?> container = anyUtils.newPlainAttr(); - container.setSchema(schema); - if (attrValue instanceof PlainAttrUniqueValue) { - container.setUniqueValue((PlainAttrUniqueValue) attrValue); - } else { - ((JSONPlainAttr) container).add(attrValue); - } - return "plainAttrs::jsonb @> '" + POJOHelper.serialize(List.of(container)).replace("'", "''") + "'::jsonb"; + ((JSONPlainAttr) container).add(attrValue); } + return "plainAttrs::jsonb @> '" + POJOHelper.serialize(List.of(container)).replace("'", "''") + "'::jsonb"; } } diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java index 88553bd260..e2c4c71f0f 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java @@ -170,11 +170,11 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO { try { switch (schema.getType()) { case Long: - Long.parseLong(value); + Long.valueOf(value); break; case Double: - Double.parseDouble(value); + Double.valueOf(value); break; case Boolean: @@ -193,7 +193,6 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO { } switch (cond.getType()) { - case ISNULL: // shouldn't occour: processed before break; diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAuditConfDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAuditConfDAO.java index 4e9acf5d11..c797b7d052 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAuditConfDAO.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAuditConfDAO.java @@ -26,7 +26,7 @@ import org.apache.syncope.core.provisioning.api.serialization.POJOHelper; public class PGJPAJSONAuditConfDAO extends AbstractJPAJSONLoggerDAO { - private static class PGMessageCriteriaBuilder extends JSONMessageCriteriaBuilder { + protected static class PGMessageCriteriaBuilder extends JSONMessageCriteriaBuilder { @Override protected String doBuild(final List<ObjectNode> containers) { diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/OJPAJSONEntityFactory.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/OJPAJSONEntityFactory.java new file mode 100644 index 0000000000..0b35c11932 --- /dev/null +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/OJPAJSONEntityFactory.java @@ -0,0 +1,30 @@ +/* + * 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. + */ +package org.apache.syncope.core.persistence.jpa.entity; + +import org.apache.syncope.core.persistence.api.dao.AnySearchDAO; +import org.apache.syncope.core.persistence.jpa.dao.OJPAJSONAnySearchDAO; + +public class OJPAJSONEntityFactory extends JPAJSONEntityFactory { + + @Override + public Class<? extends AnySearchDAO> anySearchDAOClass() { + return OJPAJSONAnySearchDAO.class; + } +} diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAJSONAnyObject.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAJSONAnyObject.java index 5fc6eeb596..3415c44414 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAJSONAnyObject.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAJSONAnyObject.java @@ -25,7 +25,6 @@ import java.util.Optional; import java.util.stream.Collectors; import javax.persistence.Entity; import javax.persistence.EntityListeners; -import javax.persistence.Lob; import javax.persistence.Table; import javax.persistence.Transient; import org.apache.syncope.core.persistence.api.entity.JSONAttributable; @@ -44,7 +43,6 @@ public class JPAJSONAnyObject extends JPAAnyObject implements JSONAttributable<A private static final long serialVersionUID = -8543654943709531885L; - @Lob private String plainAttrs; @Transient diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAJSONGroup.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAJSONGroup.java index 1366cb94e5..0ba77ff612 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAJSONGroup.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAJSONGroup.java @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.List; import javax.persistence.Entity; import javax.persistence.EntityListeners; -import javax.persistence.Lob; import javax.persistence.Table; import javax.persistence.Transient; import org.apache.syncope.core.persistence.api.entity.JSONAttributable; @@ -39,7 +38,6 @@ public class JPAJSONGroup extends JPAGroup implements JSONAttributable<Group>, G private static final long serialVersionUID = -8543654943709531885L; - @Lob private String plainAttrs; @Transient diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONLinkedAccount.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONLinkedAccount.java index 3864fb9eb1..ef5c3617ce 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONLinkedAccount.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONLinkedAccount.java @@ -24,7 +24,6 @@ import java.util.Optional; import java.util.stream.Collectors; import javax.persistence.Entity; import javax.persistence.EntityListeners; -import javax.persistence.Lob; import javax.persistence.Table; import javax.persistence.Transient; import org.apache.syncope.core.persistence.api.entity.JSONAttributable; @@ -42,7 +41,6 @@ public class JPAJSONLinkedAccount extends JPALinkedAccount implements JSONAttrib private static final long serialVersionUID = 7495284980208765032L; - @Lob private String plainAttrs; @Transient diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONUser.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONUser.java index 4eb99cfbbb..a145bab4d3 100644 --- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONUser.java +++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONUser.java @@ -26,7 +26,6 @@ import java.util.stream.Collectors; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.EntityListeners; -import javax.persistence.Lob; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.Transient; @@ -48,7 +47,6 @@ public class JPAJSONUser extends JPAUser implements JSONAttributable<User>, User private static final long serialVersionUID = -8543654943709531885L; - @Lob private String plainAttrs; @Transient diff --git a/core/persistence-jpa-json/src/main/resources/META-INF/spring-orm-ojson.xml b/core/persistence-jpa-json/src/main/resources/META-INF/spring-orm-ojson.xml new file mode 100644 index 0000000000..427948f540 --- /dev/null +++ b/core/persistence-jpa-json/src/main/resources/META-INF/spring-orm-ojson.xml @@ -0,0 +1,136 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +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. +--> +<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm + http://java.sun.com/xml/ns/persistence/orm_2_0.xsd" + version="2.0"> + + <persistence-unit-metadata> + <persistence-unit-defaults> + <entity-listeners> + <entity-listener class="org.apache.syncope.core.persistence.jpa.validation.entity.EntityValidationListener"> + <pre-persist method-name="validate"/> + <pre-update method-name="validate"/> + </entity-listener> + </entity-listeners> + </persistence-unit-defaults> + </persistence-unit-metadata> + <entity class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAJSONAnyObject"> + <attributes> + <basic name="plainAttrs"> + <column column-definition="CLOB CHECK (plainAttrs IS JSON)"/> + <lob/> + </basic> + </attributes> + </entity> + + <entity class="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup"> + <attributes> + <basic name="plainAttrs"> + <column column-definition="CLOB CHECK (plainAttrs IS JSON)"/> + <lob/> + </basic> + </attributes> + </entity> + + <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONUser"> + <attributes> + <basic name="plainAttrs"> + <column column-definition="CLOB CHECK (plainAttrs IS JSON)"/> + <lob/> + </basic> + </attributes> + </entity> + + <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONLinkedAccount"> + <attributes> + <basic name="plainAttrs"> + <column column-definition="CLOB CHECK (plainAttrs IS JSON)"/> + <lob/> + </basic> + </attributes> + </entity> + + <entity class="org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup"> + <attributes> + <many-to-one name="userOwner" target-entity="org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONUser"/> + <many-to-one name="groupOwner" target-entity="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup"/> + </attributes> + </entity> + + <entity class="org.apache.syncope.core.persistence.jpa.entity.group.JPATypeExtension"> + <attributes> + <many-to-one name="group" target-entity="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup"/> + </attributes> + </entity> + + <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUMembership"> + <attributes> + <many-to-one name="leftEnd" target-entity="org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONUser"> + <join-column name="user_id"/> + </many-to-one> + <many-to-one name="rightEnd" target-entity="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup"> + <join-column name="group_id"/> + </many-to-one> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUDynGroupMembership"> + <attributes> + <one-to-one name="group" target-entity="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup"/> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAURelationship"> + <attributes> + <many-to-one name="leftEnd" target-entity="org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONUser"> + <join-column name="user_id"/> + </many-to-one> + <many-to-one name="rightEnd" target-entity="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAJSONAnyObject"> + <join-column name="anyObject_id"/> + </many-to-one> + </attributes> + </entity> + + <entity class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAMembership"> + <attributes> + <many-to-one name="leftEnd" target-entity="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAJSONAnyObject"> + <join-column name="anyObject_id"/> + </many-to-one> + <many-to-one name="rightEnd" target-entity="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup"> + <join-column name="group_id"/> + </many-to-one> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAADynGroupMembership"> + <attributes> + <one-to-one name="group" target-entity="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup"/> + </attributes> + </entity> + <entity class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAARelationship"> + <attributes> + <many-to-one name="leftEnd" target-entity="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAJSONAnyObject"> + <join-column name="left_anyObject_id"/> + </many-to-one> + <many-to-one name="rightEnd" target-entity="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAJSONAnyObject"> + <join-column name="right_anyObject_id"/> + </many-to-one> + </attributes> + </entity> +</entity-mappings> diff --git a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories b/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories index c43e216ec2..3eea832444 100644 --- a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories +++ b/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories @@ -17,4 +17,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.apache.syncope.core.persistence.jpa.PGJPAJSONPersistenceContext,\ - org.apache.syncope.core.persistence.jpa.MyJPAJSONPersistenceContext + org.apache.syncope.core.persistence.jpa.MyJPAJSONPersistenceContext,\ + org.apache.syncope.core.persistence.jpa.OJPAJSONPersistenceContext diff --git a/core/persistence-jpa-json/src/main/resources/audit/audit_ojson.sql b/core/persistence-jpa-json/src/main/resources/audit/audit_ojson.sql new file mode 100644 index 0000000000..d4e39395f5 --- /dev/null +++ b/core/persistence-jpa-json/src/main/resources/audit/audit_ojson.sql @@ -0,0 +1,24 @@ +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. + +CREATE TABLE AuditEntry ( + EVENT_DATE TIMESTAMP, + LOGGER_LEVEL VARCHAR(255) NOT NULL, + LOGGER VARCHAR(255) NOT NULL, + MESSAGE CLOB CHECK (MESSAGE IS JSON) NOT NULL, + THROWABLE CLOB +); diff --git a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories b/core/persistence-jpa-json/src/main/resources/core-ojson.properties similarity index 50% copy from core/persistence-jpa-json/src/main/resources/META-INF/spring.factories copy to core/persistence-jpa-json/src/main/resources/core-ojson.properties index c43e216ec2..aecedde8e5 100644 --- a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories +++ b/core/persistence-jpa-json/src/main/resources/core-ojson.properties @@ -15,6 +15,20 @@ # specific language governing permissions and limitations # under the License. -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.apache.syncope.core.persistence.jpa.PGJPAJSONPersistenceContext,\ - org.apache.syncope.core.persistence.jpa.MyJPAJSONPersistenceContext +persistence.indexesXML=classpath:ojson/indexes.xml +persistence.viewsXML=classpath:ojson/views.xml + +persistence.domain[0].key=Master +persistence.domain[0].jdbcDriver=oracle.jdbc.OracleDriver +persistence.domain[0].jdbcURL=jdbc:oracle:thin:@localhost:1521/XEPDB1 +persistence.domain[0].schema=SYNCOPE +persistence.domain[0].dbUsername=syncope +persistence.domain[0].dbPassword=syncope +persistence.domain[0].databasePlatform=org.apache.openjpa.jdbc.sql.OracleDictionary +persistence.domain[0].orm=META-INF/spring-orm-ojson.xml +persistence.domain[0].auditSql=audit_ojson.sql +persistence.domain[0].poolMaxActive=10 +persistence.domain[0].poolMinIdle=2 + +provisioning.quartz.delegate=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate +provisioning.quartz.sql=tables_oracle.sql diff --git a/core/persistence-jpa-json/src/main/resources/myjson/views.xml b/core/persistence-jpa-json/src/main/resources/myjson/views.xml index 1744dc06d9..7c351412a7 100644 --- a/core/persistence-jpa-json/src/main/resources/myjson/views.xml +++ b/core/persistence-jpa-json/src/main/resources/myjson/views.xml @@ -51,7 +51,7 @@ under the License. CREATE VIEW user_search AS SELECT u.id as any_id, u.*, attrs.* - FROM SyncopeUser u, JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' COLUMNS ( + FROM SyncopeUser u LEFT OUTER JOIN JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' COLUMNS ( plainSchema VARCHAR(255) PATH '$.schema', NESTED PATH '$.values[*]' COLUMNS ( binaryValue LONGBLOB PATH '$.binaryValue', @@ -61,7 +61,7 @@ under the License. longValue BIGINT(20) PATH '$.longValue', stringValue VARCHAR(255) PATH '$.stringValue'), attrUniqueValue JSON PATH '$.uniqueValue') - ) AS attrs + ) AS attrs ON 1=1 </entry> <entry key="user_search_urelationship"> CREATE VIEW user_search_urelationship AS @@ -121,7 +121,7 @@ under the License. CREATE VIEW anyObject_search AS SELECT a.id as any_id, a.*, attrs.* - FROM AnyObject a, JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' COLUMNS ( + FROM AnyObject a LEFT OUTER JOIN JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' COLUMNS ( plainSchema VARCHAR(255) PATH '$.schema', NESTED PATH '$.values[*]' COLUMNS ( binaryValue LONGBLOB PATH '$.binaryValue', @@ -131,7 +131,7 @@ under the License. longValue BIGINT(20) PATH '$.longValue', stringValue VARCHAR(255) PATH '$.stringValue'), attrUniqueValue JSON PATH '$.uniqueValue') - ) AS attrs + ) AS attrs ON 1=1 </entry> <entry key="anyObject_search_arelationship"> CREATE VIEW anyObject_search_arelationship AS @@ -171,7 +171,7 @@ under the License. CREATE VIEW group_search AS SELECT g.id as any_id, g.*, attrs.* - FROM SyncopeGroup g, JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' COLUMNS ( + FROM SyncopeGroup g LEFT OUTER JOIN JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' COLUMNS ( plainSchema VARCHAR(255) PATH '$.schema', NESTED PATH '$.values[*]' COLUMNS ( binaryValue LONGBLOB PATH '$.binaryValue', @@ -181,7 +181,7 @@ under the License. longValue BIGINT(20) PATH '$.longValue', stringValue VARCHAR(255) PATH '$.stringValue'), attrUniqueValue JSON PATH '$.uniqueValue') - ) AS attrs + ) AS attrs ON 1=1 </entry> <entry key="group_search_auxClass"> CREATE VIEW group_search_auxClass AS diff --git a/core/persistence-jpa-json/src/main/resources/ojson/indexes.xml b/core/persistence-jpa-json/src/main/resources/ojson/indexes.xml new file mode 100644 index 0000000000..4d203d762b --- /dev/null +++ b/core/persistence-jpa-json/src/main/resources/ojson/indexes.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- +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. +--> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> + <comment>Additional indexes (in respect to JPA's)</comment> + + <!-- The following indexes require Oracle TEXT to be installed on the given Oracle database: + http://dbaflavours.blogspot.com/2012/09/ora-29833-indextype-does-not-exist_18.html --> + <entry key="AnyObject_plainAttrs_Index">CREATE SEARCH INDEX AnyObject_plainAttrs_Index ON AnyObject(plainAttrs) FOR JSON</entry> + <entry key="SyncopeGroup_plainAttrs_Index">CREATE SEARCH INDEX SyncopeGroup_plainAttrs_Index ON SyncopeGroup(plainAttrs) FOR JSON</entry> + <entry key="SyncopeUser_plainAttrs_Index">CREATE SEARCH INDEX SyncopeUser_plainAttrs_Index ON SyncopeUser(plainAttrs) FOR JSON</entry> + <entry key="LinkedAccount_plainAttrs_Index">CREATE SEARCH INDEX LinkedAccount_plainAttrs_Index ON LinkedAccount(plainAttrs) FOR JSON</entry> + + <entry key="UDynGroupMembers_any_id">CREATE INDEX UDynGroupMembers_any_id ON UDynGroupMembers(any_id)</entry> + <entry key="UDynGroupMembers_group_id">CREATE INDEX UDynGroupMembers_group_id ON UDynGroupMembers(group_id)</entry> + <entry key="ADynGroupMembers_any_id">CREATE INDEX ADynGroupMembers_any_id ON ADynGroupMembers(any_id)</entry> + <entry key="ADynGroupMembers_group_id">CREATE INDEX ADynGroupMembers_group_id ON ADynGroupMembers(group_id)</entry> + + <entry key="DynRoleMembers_any_id">CREATE INDEX DynRoleMembers_any_id ON DynRoleMembers(any_id)</entry> + <entry key="DynRoleMembers_role_id">CREATE INDEX DynRoleMembers_role_id ON DynRoleMembers(role_id)</entry> + + <entry key="DynRealmMembers_any_id">CREATE INDEX DynRealmMembers_any_id ON DynRealmMembers(any_id)</entry> + <entry key="DynRealmMembers_realm_id">CREATE INDEX DynRealmMembers_dynRealm_id ON DynRealmMembers(dynRealm_id)</entry> + + <entry key="UMembership_GroupIndex">CREATE INDEX UMembership_GroupIndex ON UMembership(group_id)</entry> + <entry key="UMembership_UserIndex">CREATE INDEX UMembership_UserIndex ON UMembership(user_id)</entry> + <entry key="AMembership_GroupIndex">CREATE INDEX AMembership_GroupIndex ON AMembership(group_id)</entry> + <entry key="AMembership_AnyObjectIndex">CREATE INDEX AMembership_AnyObjectIndex ON AMembership(anyObject_id)</entry> + + <entry key="URelationship_RightIndex">CREATE INDEX URelationship_RightIndex ON URelationship(anyObject_id)</entry> + <entry key="URelationship_LeftIndex">CREATE INDEX URelationship_LeftIndex ON URelationship(user_id)</entry> + <entry key="ARelationship_RightIndex">CREATE INDEX ARelationship_RightIndex ON ARelationship(right_anyObject_id)</entry> + <entry key="ARelationship_AnyObjectIndex">CREATE INDEX ARelationship_AnyObjectIndex ON ARelationship(left_anyObject_id)</entry> + + <entry key="Task_executedIndex">CREATE INDEX Task_executedIndex ON NotificationTask(executed)</entry> + <entry key="TaskExec1_TaskIdIndex">CREATE INDEX TaskExec1_TaskIdIndex ON PropagationTaskExec(task_id)</entry> + <entry key="TaskExec2_TaskIdIndex">CREATE INDEX TaskExec2_TaskIdIndex ON PullTaskExec(task_id)</entry> + <entry key="TaskExec3_TaskIdIndex">CREATE INDEX TaskExec3_TaskIdIndex ON PushTaskExec(task_id)</entry> + <entry key="TaskExec4_TaskIdIndex">CREATE INDEX TaskExec4_TaskIdIndex ON NotificationTaskExec(task_id)</entry> + <entry key="TaskExec5_TaskIdIndex">CREATE INDEX TaskExec5_TaskIdIndex ON SchedTaskExec(task_id)</entry> + <entry key="ATPullTask_PullTaskIndex">CREATE INDEX ATPullTask_PullTaskIndex ON AnyTemplatePullTask(pullTask_id)</entry> +</properties> diff --git a/core/persistence-jpa-json/src/main/resources/myjson/views.xml b/core/persistence-jpa-json/src/main/resources/ojson/views.xml similarity index 68% copy from core/persistence-jpa-json/src/main/resources/myjson/views.xml copy to core/persistence-jpa-json/src/main/resources/ojson/views.xml index 1744dc06d9..0bc2c43286 100644 --- a/core/persistence-jpa-json/src/main/resources/myjson/views.xml +++ b/core/persistence-jpa-json/src/main/resources/ojson/views.xml @@ -51,17 +51,23 @@ under the License. CREATE VIEW user_search AS SELECT u.id as any_id, u.*, attrs.* - FROM SyncopeUser u, JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' COLUMNS ( - plainSchema VARCHAR(255) PATH '$.schema', - NESTED PATH '$.values[*]' COLUMNS ( - binaryValue LONGBLOB PATH '$.binaryValue', - booleanValue INT PATH '$.booleanValue', - dateValue VARCHAR(32) PATH '$.dateValue', - doubleValue DOUBLE PATH '$.doubleValue', - longValue BIGINT(20) PATH '$.longValue', - stringValue VARCHAR(255) PATH '$.stringValue'), - attrUniqueValue JSON PATH '$.uniqueValue') - ) AS attrs + FROM SyncopeUser u LEFT OUTER JOIN JSON_TABLE(u.plainAttrs, '$[*]' COLUMNS ( + plainSchema PATH '$.schema', + NESTED PATH '$.uniqueValue' COLUMNS( + ubinaryValue PATH '$.binaryValue', + ubooleanValue PATH '$.booleanValue', + udateValue PATH '$.dateValue', + ulongValue PATH '$.longValue', + udoubleValue PATH '$.doubleValue', + ustringValue PATH '$.stringValue'), + NESTED PATH '$.values[*]' COLUMNS( + binaryValue FORMAT JSON WITH WRAPPER PATH '$.binaryValue', + booleanValue FORMAT JSON WITH WRAPPER PATH '$.booleanValue', + dateValue FORMAT JSON WITH WRAPPER PATH '$.dateValue', + longValue FORMAT JSON WITH WRAPPER PATH '$.longValue', + doubleValue FORMAT JSON WITH WRAPPER PATH '$.doubleValue', + stringValue FORMAT JSON WITH WRAPPER PATH '$.stringValue') + )) AS attrs ON 1=1 </entry> <entry key="user_search_urelationship"> CREATE VIEW user_search_urelationship AS @@ -121,17 +127,23 @@ under the License. CREATE VIEW anyObject_search AS SELECT a.id as any_id, a.*, attrs.* - FROM AnyObject a, JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' COLUMNS ( - plainSchema VARCHAR(255) PATH '$.schema', - NESTED PATH '$.values[*]' COLUMNS ( - binaryValue LONGBLOB PATH '$.binaryValue', - booleanValue INT PATH '$.booleanValue', - dateValue VARCHAR(32) PATH '$.dateValue', - doubleValue DOUBLE PATH '$.doubleValue', - longValue BIGINT(20) PATH '$.longValue', - stringValue VARCHAR(255) PATH '$.stringValue'), - attrUniqueValue JSON PATH '$.uniqueValue') - ) AS attrs + FROM AnyObject a LEFT OUTER JOIN JSON_TABLE(a.plainAttrs, '$[*]' COLUMNS ( + plainSchema PATH '$.schema', + NESTED PATH '$.uniqueValue' COLUMNS( + ubinaryValue PATH '$.binaryValue', + ubooleanValue PATH '$.booleanValue', + udateValue PATH '$.dateValue', + ulongValue PATH '$.longValue', + udoubleValue PATH '$.doubleValue', + ustringValue PATH '$.stringValue'), + NESTED PATH '$.values[*]' COLUMNS( + binaryValue FORMAT JSON WITH WRAPPER PATH '$.binaryValue', + booleanValue FORMAT JSON WITH WRAPPER PATH '$.booleanValue', + dateValue FORMAT JSON WITH WRAPPER PATH '$.dateValue', + longValue FORMAT JSON WITH WRAPPER PATH '$.longValue', + doubleValue FORMAT JSON WITH WRAPPER PATH '$.doubleValue', + stringValue FORMAT JSON WITH WRAPPER PATH '$.stringValue') + )) AS attrs ON 1=1 </entry> <entry key="anyObject_search_arelationship"> CREATE VIEW anyObject_search_arelationship AS @@ -171,17 +183,23 @@ under the License. CREATE VIEW group_search AS SELECT g.id as any_id, g.*, attrs.* - FROM SyncopeGroup g, JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' COLUMNS ( - plainSchema VARCHAR(255) PATH '$.schema', - NESTED PATH '$.values[*]' COLUMNS ( - binaryValue LONGBLOB PATH '$.binaryValue', - booleanValue INT PATH '$.booleanValue', - dateValue VARCHAR(32) PATH '$.dateValue', - doubleValue DOUBLE PATH '$.doubleValue', - longValue BIGINT(20) PATH '$.longValue', - stringValue VARCHAR(255) PATH '$.stringValue'), - attrUniqueValue JSON PATH '$.uniqueValue') - ) AS attrs + FROM SyncopeGroup g LEFT OUTER JOIN JSON_TABLE(g.plainAttrs, '$[*]' COLUMNS ( + plainSchema PATH '$.schema', + NESTED PATH '$.uniqueValue' COLUMNS( + ubinaryValue PATH '$.binaryValue', + ubooleanValue PATH '$.booleanValue', + udateValue PATH '$.dateValue', + ulongValue PATH '$.longValue', + udoubleValue PATH '$.doubleValue', + ustringValue PATH '$.stringValue'), + NESTED PATH '$.values[*]' COLUMNS( + binaryValue FORMAT JSON WITH WRAPPER PATH '$.binaryValue', + booleanValue FORMAT JSON WITH WRAPPER PATH '$.booleanValue', + dateValue FORMAT JSON WITH WRAPPER PATH '$.dateValue', + longValue FORMAT JSON WITH WRAPPER PATH '$.longValue', + doubleValue FORMAT JSON WITH WRAPPER PATH '$.doubleValue', + stringValue FORMAT JSON WITH WRAPPER PATH '$.stringValue') + )) AS attrs ON 1=1 </entry> <entry key="group_search_auxClass"> CREATE VIEW group_search_auxClass AS diff --git a/core/persistence-jpa-json/src/main/resources/persistence-enhance.xml b/core/persistence-jpa-json/src/main/resources/persistence-enhance.xml index 718f22953e..0c6e795b93 100644 --- a/core/persistence-jpa-json/src/main/resources/persistence-enhance.xml +++ b/core/persistence-jpa-json/src/main/resources/persistence-enhance.xml @@ -24,7 +24,7 @@ under the License. version="2.0"> <persistence-unit name="Master"> - <mapping-file>META-INF/spring-orm-pgjsonb.xml</mapping-file> + <mapping-file>META-INF/spring-orm-${orm}.xml</mapping-file> <validation-mode>NONE</validation-mode> </persistence-unit> diff --git a/core/persistence-jpa-json/src/test/java/org/apache/syncope/core/persistence/jpa/JPAJSONTestContextCustomizer.java b/core/persistence-jpa-json/src/test/java/org/apache/syncope/core/persistence/jpa/JPAJSONTestContextCustomizer.java index 8700e318bc..8a73334730 100644 --- a/core/persistence-jpa-json/src/test/java/org/apache/syncope/core/persistence/jpa/JPAJSONTestContextCustomizer.java +++ b/core/persistence-jpa-json/src/test/java/org/apache/syncope/core/persistence/jpa/JPAJSONTestContextCustomizer.java @@ -22,7 +22,6 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; -import org.springframework.context.support.AbstractApplicationContext; import org.springframework.test.context.ContextCustomizer; import org.springframework.test.context.MergedContextConfiguration; import org.springframework.test.context.support.TestPropertySourceUtils; @@ -33,26 +32,39 @@ public class JPAJSONTestContextCustomizer implements ContextCustomizer { if (ctx instanceof BeanDefinitionRegistry) { return (BeanDefinitionRegistry) ctx; } - if (ctx instanceof AbstractApplicationContext) { - return (BeanDefinitionRegistry) ((AbstractApplicationContext) ctx).getBeanFactory(); + if (ctx instanceof ConfigurableApplicationContext) { + return (BeanDefinitionRegistry) ((ConfigurableApplicationContext) ctx).getBeanFactory(); } throw new IllegalStateException("Could not locate BeanDefinitionRegistry"); } @Override public void customizeContext(final ConfigurableApplicationContext ctx, final MergedContextConfiguration cfg) { - if ("pgjsonb".equals(System.getProperty("profileId"))) { - TestPropertySourceUtils.addInlinedPropertiesToEnvironment( - ctx, - "provisioning.quartz.delegate=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate"); - } else if ("myjson".equals(System.getProperty("profileId"))) { - TestPropertySourceUtils.addInlinedPropertiesToEnvironment( - ctx, - "provisioning.quartz.delegate=org.quartz.impl.jdbcjobstore.StdJDBCDelegate"); + switch (System.getProperty("profileId")) { + case "pgjsonb": + TestPropertySourceUtils.addInlinedPropertiesToEnvironment( + ctx, + "provisioning.quartz.sql=tables_postgres.sql"); + break; + + case "myjson": + TestPropertySourceUtils.addInlinedPropertiesToEnvironment( + ctx, + "provisioning.quartz.sql=tables_mysql_innodb.sql"); + break; + + case "ojson": + TestPropertySourceUtils.addInlinedPropertiesToEnvironment( + ctx, + "provisioning.quartz.sql=tables_oracle.sql"); + break; + + default: } AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(getBeanDefinitionRegistry(ctx)); reader.registerBean(PGJPAJSONPersistenceContext.class, "PGJPAJSONPersistenceContext"); reader.registerBean(MyJPAJSONPersistenceContext.class, "MyJPAJSONPersistenceContext"); + reader.registerBean(OJPAJSONPersistenceContext.class, "OJPAJSONPersistenceContext"); } } diff --git a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories b/core/persistence-jpa-json/src/test/resources/core-ojson-test.properties similarity index 70% copy from core/persistence-jpa-json/src/main/resources/META-INF/spring.factories copy to core/persistence-jpa-json/src/test/resources/core-ojson-test.properties index c43e216ec2..972a4bfd52 100644 --- a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories +++ b/core/persistence-jpa-json/src/test/resources/core-ojson-test.properties @@ -15,6 +15,12 @@ # specific language governing permissions and limitations # under the License. -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.apache.syncope.core.persistence.jpa.PGJPAJSONPersistenceContext,\ - org.apache.syncope.core.persistence.jpa.MyJPAJSONPersistenceContext +security.adminUser=${adminUser} +security.anonymousUser=${anonymousUser} +security.jwsKey=${jwsKey} +security.secretKey=${secretKey} + +persistence.domain[0].jdbcURL=jdbc:oracle:thin:@${DB_CONTAINER_IP}:1521/XEPDB1 +#persistence.domain[0].jdbcURL=jdbc:oracle:thin:@192.168.0.176:1521/orcl + +provisioning.connIdLocation=${connid.location} diff --git a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml index bed2f381a2..942bf5e987 100644 --- a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml +++ b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml @@ -273,8 +273,9 @@ under the License. <AnyObject id="9e1d130c-d6a3-48b1-98b3-182477ed0688" name="Epson Stylus Color" realm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c" type_id="PRINTER" creator="admin" lastModifier="admin" - creationDate="2021-04-15 12:45:00" lastChangeDate="2010-10-20 11:00:00"/> - + creationDate="2021-04-15 12:45:00" lastChangeDate="2010-10-20 11:00:00" + plainAttrs="[]"/> + <ARelationship id="11a0ec66-b59b-428a-af3d-f856950ff1c5" type_id="neighborhood" left_anyObject_id="fc6dbc3a-6c07-4965-8781-921e7401a4a5" right_anyObject_id="8559d14d-58c2-46eb-a2d4-a7d35161e8f8"/> diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java index 3328a8f9e0..023b370876 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java @@ -72,6 +72,11 @@ import org.apache.syncope.core.provisioning.api.utils.RealmUtils; */ public class JPAAnySearchDAO extends AbstractAnySearchDAO { + protected static final String SELECT_COLS_FROM_VIEW = + "any_id,creationContext,creationDate,creator,lastChangeContext," + + "lastChangeDate,lastModifier,status,changePwdDate,cipherAlgorithm,failedLogins," + + "lastLoginDate,mustChangePassword,suspended,username"; + public JPAAnySearchDAO( final RealmDAO realmDAO, final DynRealmDAO dynRealmDAO, diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java index f0463a8d31..bb9a7919cd 100644 --- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java +++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java @@ -171,10 +171,10 @@ public class UserTest extends AbstractTest { @Test public void findByPlainAttrBooleanValue() { - final UPlainAttrValue coolValue = entityFactory.newEntity(UPlainAttrValue.class); + UPlainAttrValue coolValue = entityFactory.newEntity(UPlainAttrValue.class); coolValue.setBooleanValue(true); - final List<User> list = userDAO.findByPlainAttrValue(plainSchemaDAO.find("cool"), coolValue, false); + List<User> list = userDAO.findByPlainAttrValue(plainSchemaDAO.find("cool"), coolValue, false); assertEquals(1, list.size()); } diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml index f67e2b6eb4..571a6f2f93 100644 --- a/fit/core-reference/pom.xml +++ b/fit/core-reference/pom.xml @@ -1133,17 +1133,23 @@ under the License. </profile> <profile> - <id>oracle-it</id> + <id>ojson-it</id> <properties> <jdbcdriver.groupId>com.oracle.database.jdbc</jdbcdriver.groupId> <jdbcdriver.artifactId>ojdbc11</jdbcdriver.artifactId> <cargo.deployable.ping.timeout>120000</cargo.deployable.ping.timeout> - <spring.profiles.active>embedded,oracle</spring.profiles.active> + <spring.profiles.active>embedded,ojson</spring.profiles.active> </properties> <dependencies> + <dependency> + <groupId>org.apache.syncope.core</groupId> + <artifactId>syncope-core-persistence-jpa-json</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc11</artifactId> @@ -1174,7 +1180,7 @@ under the License. <images> <image> <alias>oracle</alias> - <name>gvenzl/oracle-xe:18-slim</name> + <name>gvenzl/oracle-xe:21-slim</name> <run> <env> <ORACLE_PASSWORD>password</ORACLE_PASSWORD> @@ -1231,10 +1237,110 @@ under the License. <resources> <resource> - <directory>src/main/resources/oracle</directory> + <directory>${basedir}/../../core/persistence-jpa-json/src/test/resources/domains</directory> + <targetPath>${project.build.outputDirectory}/domains</targetPath> <filtering>true</filtering> </resource> </resources> + </build> + </profile> + + <profile> + <id>oracle-it</id> + + <properties> + <jdbcdriver.groupId>com.oracle.database.jdbc</jdbcdriver.groupId> + <jdbcdriver.artifactId>ojdbc11</jdbcdriver.artifactId> + <cargo.deployable.ping.timeout>120000</cargo.deployable.ping.timeout> + + <spring.profiles.active>embedded,oracle</spring.profiles.active> + </properties> + + <dependencies> + <dependency> + <groupId>com.oracle.database.jdbc</groupId> + <artifactId>ojdbc11</artifactId> + <version>${jdbc.oracle.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <defaultGoal>clean verify</defaultGoal> + + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-failsafe-plugin</artifactId> + <inherited>true</inherited> + <configuration> + <includes> + <include>**/org/apache/syncope/fit/core/*ITCase.java</include> + </includes> + </configuration> + </plugin> + + <plugin> + <groupId>io.fabric8</groupId> + <artifactId>docker-maven-plugin</artifactId> + <configuration> + <images> + <image> + <alias>oracle</alias> + <name>gvenzl/oracle-xe:21-slim</name> + <run> + <env> + <ORACLE_PASSWORD>password</ORACLE_PASSWORD> + <APP_USER>syncope</APP_USER> + <APP_USER_PASSWORD>syncope</APP_USER_PASSWORD> + </env> + <wait> + <log>DATABASE IS READY TO USE</log> + <time>120000</time> + </wait> + </run> + </image> + </images> + </configuration> + <executions> + <execution> + <id>buid-oracle</id> + <phase>initialize</phase> + <goals> + <goal>build</goal> + </goals> + </execution> + <execution> + <id>start-oracle</id> + <phase>pre-integration-test</phase> + <goals> + <goal>start</goal> + </goals> + </execution> + <execution> + <id>stop-oracle</id> + <phase>post-integration-test</phase> + <goals> + <goal>stop</goal> + <goal>remove</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.codehaus.cargo</groupId> + <artifactId>cargo-maven3-plugin</artifactId> + <inherited>true</inherited> + <configuration> + <container> + <systemProperties> + <DB_CONTAINER_IP>${docker.container.oracle.ip}</DB_CONTAINER_IP> + </systemProperties> + </container> + </configuration> + </plugin> + </plugins> </build> </profile> diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java index 3e09473641..a63671f3f9 100644 --- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java +++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java @@ -41,6 +41,7 @@ import org.apache.syncope.common.lib.report.StaticReportletConf; import org.apache.syncope.common.lib.report.UserReportletConf; import org.apache.syncope.common.lib.types.IdMImplementationType; import org.apache.syncope.common.lib.types.IdRepoImplementationType; +import org.apache.syncope.core.logic.job.MacroRunJobDelegate; import org.apache.syncope.core.persistence.api.ImplementationLookup; import org.apache.syncope.core.persistence.api.dao.AccountRule; import org.apache.syncope.core.persistence.api.dao.AnySearchDAO; @@ -54,6 +55,8 @@ import org.apache.syncope.core.persistence.jpa.attrvalue.validation.BinaryValida import org.apache.syncope.core.persistence.jpa.attrvalue.validation.EmailAddressValidator; import org.apache.syncope.core.persistence.jpa.dao.DefaultPullCorrelationRule; import org.apache.syncope.core.persistence.jpa.dao.DefaultPushCorrelationRule; +import org.apache.syncope.core.provisioning.java.job.ExpiredAccessTokenCleanup; +import org.apache.syncope.core.provisioning.java.job.ExpiredBatchCleanup; import org.apache.syncope.core.provisioning.java.job.report.AuditReportlet; import org.apache.syncope.core.provisioning.java.job.report.GroupReportlet; import org.apache.syncope.core.provisioning.java.job.report.ReconciliationReportlet; @@ -68,6 +71,8 @@ import org.apache.syncope.core.provisioning.java.pushpull.DBPasswordPullActions; import org.apache.syncope.core.provisioning.java.pushpull.DefaultProvisionSorter; import org.apache.syncope.core.provisioning.java.pushpull.LDAPMembershipPullActions; import org.apache.syncope.core.provisioning.java.pushpull.LDAPPasswordPullActions; +import org.apache.syncope.core.provisioning.java.pushpull.PullJobDelegate; +import org.apache.syncope.core.provisioning.java.pushpull.PushJobDelegate; import org.apache.syncope.core.spring.policy.DefaultAccountRule; import org.apache.syncope.core.spring.policy.DefaultPasswordRule; import org.apache.syncope.core.spring.policy.HaveIBeenPwnedPasswordRule; @@ -160,6 +165,11 @@ public class ITImplementationLookup implements ImplementationLookup { put(IdRepoImplementationType.ITEM_TRANSFORMER, classNames); classNames = new HashSet<>(); + classNames.add(MacroRunJobDelegate.class.getName()); + classNames.add(PullJobDelegate.class.getName()); + classNames.add(PushJobDelegate.class.getName()); + classNames.add(ExpiredAccessTokenCleanup.class.getName()); + classNames.add(ExpiredBatchCleanup.class.getName()); classNames.add(TestSampleJobDelegate.class.getName()); put(IdRepoImplementationType.TASKJOB_DELEGATE, classNames); diff --git a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories b/fit/core-reference/src/main/resources/core-ojson.properties similarity index 50% copy from core/persistence-jpa-json/src/main/resources/META-INF/spring.factories copy to fit/core-reference/src/main/resources/core-ojson.properties index c43e216ec2..e621a63a37 100644 --- a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories +++ b/fit/core-reference/src/main/resources/core-ojson.properties @@ -15,6 +15,20 @@ # specific language governing permissions and limitations # under the License. -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.apache.syncope.core.persistence.jpa.PGJPAJSONPersistenceContext,\ - org.apache.syncope.core.persistence.jpa.MyJPAJSONPersistenceContext +persistence.indexesXML=classpath:ojson/indexes.xml +persistence.viewsXML=classpath:ojson/views.xml + +persistence.domain[0].key=Master +persistence.domain[0].jdbcDriver=oracle.jdbc.OracleDriver +persistence.domain[0].jdbcURL=jdbc:oracle:thin:@${DB_CONTAINER_IP}:1521/XEPDB1 +persistence.domain[0].schema=SYNCOPE +persistence.domain[0].dbUsername=syncope +persistence.domain[0].dbPassword=syncope +persistence.domain[0].databasePlatform=org.apache.openjpa.jdbc.sql.OracleDictionary +persistence.domain[0].orm=META-INF/spring-orm-ojson.xml +persistence.domain[0].auditSql=audit_ojson.sql +persistence.domain[0].poolMaxActive=10 +persistence.domain[0].poolMinIdle=2 + +provisioning.quartz.delegate=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate +provisioning.quartz.sql=tables_oracle.sql diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java index 5a6c17d32b..c7ddf8fca2 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java @@ -216,28 +216,28 @@ public class AnyObjectITCase extends AbstractITCase { @Test public void issueSYNCOPE1472() { // 1. assign resource-db-scripted again to Canon MF 8030cn and update twice - AnyObjectUR anyObjectPatch = new AnyObjectUR(); - anyObjectPatch.setKey("8559d14d-58c2-46eb-a2d4-a7d35161e8f8"); - anyObjectPatch.getResources().add(new StringPatchItem.Builder().value(RESOURCE_NAME_DBSCRIPTED).build()); - anyObjectPatch.getAuxClasses().add(new StringPatchItem.Builder().value("csv").build()); + AnyObjectUR updateReq = new AnyObjectUR(); + updateReq.setKey("8559d14d-58c2-46eb-a2d4-a7d35161e8f8"); + updateReq.getResources().add(new StringPatchItem.Builder().value(RESOURCE_NAME_DBSCRIPTED).build()); + updateReq.getAuxClasses().add(new StringPatchItem.Builder().value("csv").build()); for (int i = 0; i < 2; i++) { - updateAnyObject(anyObjectPatch); + updateAnyObject(updateReq); } // 2. remove resources and auxiliary classes - anyObjectPatch.getResources().clear(); - anyObjectPatch.getResources().add(new StringPatchItem.Builder() + updateReq.getResources().clear(); + updateReq.getResources().add(new StringPatchItem.Builder() .value(RESOURCE_NAME_DBSCRIPTED) .operation(PatchOperation.DELETE) .build()); - anyObjectPatch.getAuxClasses().clear(); - anyObjectPatch.getAuxClasses().add(new StringPatchItem.Builder() + updateReq.getAuxClasses().clear(); + updateReq.getAuxClasses().add(new StringPatchItem.Builder() .value("csv") .operation(PatchOperation.DELETE) .build()); - updateAnyObject(anyObjectPatch); + updateAnyObject(updateReq); AnyObjectTO printer = ANY_OBJECT_SERVICE.read("8559d14d-58c2-46eb-a2d4-a7d35161e8f8"); assertFalse(printer.getResources().contains(RESOURCE_NAME_DBSCRIPTED), "Should not contain removed resources"); diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java index d7a990f6aa..03dfcaee69 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java @@ -598,7 +598,8 @@ public class AuditITCase extends AbstractITCase { .entityKey(pullFromLDAP.getKey()) .page(1) .size(10) - .events(List.of("create", "update", "matchingrule_update", "unmatchingrule_assign", + .events(List.of( + "create", "update", "matchingrule_update", "unmatchingrule_assign", "unmatchingrule_provision")) .result(AuditElements.Result.SUCCESS) .build()).getTotalCount()); diff --git a/pom.xml b/pom.xml index e6b3162d39..93081efb1f 100644 --- a/pom.xml +++ b/pom.xml @@ -2380,6 +2380,7 @@ under the License. <postgresqlJDBC>${jdbc.postgresql.version}</postgresqlJDBC> <mysqlJDBC>${jdbc.mysql.version}</mysqlJDBC> <mariadbJDBC>${jdbc.mariadb.version}</mariadbJDBC> + <oracleJDBC>${jdbc.oracle.version}</oracleJDBC> <sqlserverJDBC>${jdbc.mssql.version}</sqlserverJDBC> <year>${year}</year> <numbered>true</numbered> diff --git a/src/main/asciidoc/getting-started/systemRequirements.adoc b/src/main/asciidoc/getting-started/systemRequirements.adoc index ee4d38c6d5..6dfcaebe65 100644 --- a/src/main/asciidoc/getting-started/systemRequirements.adoc +++ b/src/main/asciidoc/getting-started/systemRequirements.adoc @@ -47,5 +47,5 @@ Apache Syncope {docVersion} is verified with the recent versions of the followin . http://www.postgresql.org/[PostgreSQL^] (>= {postgresql}, JDBC driver >= {postgresqlJDBC}) . https://mariadb.org/[MariaDB^] (>= {mariadb}, JDBC driver >= {mariadbJDBC}) . http://www.mysql.com/[MySQL^] (>= {mysql}, JDBC driver >= {mysqlJDBC}) - . https://www.oracle.com/database/index.html[Oracle Database^] (>= 11g, JDBC driver >= ojdbc8 12.2.0.1) - . http://www.microsoft.com/en-us/server-cloud/products/sql-server/[MS SQL Server^] (>= 2017, JDBC driver >= {sqlserverJDBC}8) + . https://www.oracle.com/database/index.html[Oracle Database^] (>= 19c, JDBC driver >= ojdbc11 {oracleJDBC}) + . http://www.microsoft.com/en-us/server-cloud/products/sql-server/[MS SQL Server^] (>= 2017, JDBC driver >= {sqlserverJDBC}11) diff --git a/src/main/asciidoc/reference-guide/configuration/dbms.adoc b/src/main/asciidoc/reference-guide/configuration/dbms.adoc index 5638a47a66..0f91d2ffc3 100644 --- a/src/main/asciidoc/reference-guide/configuration/dbms.adoc +++ b/src/main/asciidoc/reference-guide/configuration/dbms.adoc @@ -240,7 +240,7 @@ This assumes that you have a MariaDB instance running on localhost, listening on ==== Oracle Database [NOTE] -Apache Syncope {docVersion} is verified with Oracle database >= 11g and JDBC driver >= ojdbc8 12.2.0.1. +Apache Syncope {docVersion} is verified with Oracle database >= 19c and JDBC driver >= ojdbc11 {oracleJDBC}. Create @@ -274,6 +274,59 @@ for the Core application. This assumes that you have an Oracle instance running on localhost, listening on its default port 1521 with a database `syncope` under tablespace `SYNCOPE`, fully accessible by user `syncope` with password `syncope`. +==== Oracle Database (JSON) + +[NOTE] +With the configurations reported below, Apache Syncope will leverage the +https://docs.oracle.com/en/database/oracle/oracle-database/19/adjsn/[JSON^] features. + +[NOTE] +Apache Syncope {docVersion} is verified with Oracle database >= 19c and JDBC driver >= ojdbc11 {oracleJDBC}. + +Add the following dependency to `core/pom.xml`: + +[source,xml,subs="verbatim,attributes"] +---- +<dependency> + <groupId>org.apache.syncope.core</groupId> + <artifactId>syncope-core-persistence-jpa-json</artifactId> + <version>${syncope.version}</version> +</dependency> +---- + +Create + +[source] +.... +persistence.indexesXML=classpath:ojson/indexes.xml +persistence.viewsXML=classpath:ojson/views.xml + +persistence.domain[0].key=Master +persistence.domain[0].jdbcDriver=oracle.jdbc.OracleDriver +persistence.domain[0].jdbcURL=jdbc:postgresql://${DB_CONTAINER_IP}:5432/syncope?stringtype=unspecified +persistence.domain[0].schema=SYNCOPE +persistence.domain[0].dbUsername=syncope +persistence.domain[0].dbPassword=syncope +persistence.domain[0].databasePlatform=org.apache.openjpa.jdbc.sql.OracleDictionary +persistence.domain[0].orm=META-INF/spring-orm-ojson.xml +persistence.domain[0].auditSql=audit_ojson.sql +persistence.domain[0].poolMaxActive=10 +persistence.domain[0].poolMinIdle=2 + +provisioning.quartz.delegate=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate +provisioning.quartz.sql=tables_oracle.sql +.... + +as `core/src/main/resources/core-ojson.properties`. + +Do not forget to include `ojson` as +https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.profiles.adding-active-profiles[Spring Boot profile^] +for the Core application. + +[WARNING] +This assumes that you have an Oracle instance running on localhost, listening on its default port 1521 with a database +`syncope` under tablespace `SYNCOPE`, fully accessible by user `syncope` with password `syncope`. + ==== MS SQL Server [NOTE]