You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2018/12/03 12:18:54 UTC
[syncope] 01/01: [SYNCOPE-1400] Adding support for MySQL 8 via
OpenJPA 3.0.1 + [SYNCOPE-1401] Adding support for MySQL with JSON type
This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch SYNCOPE-1400_SYNCOPE-1401
in repository https://gitbox.apache.org/repos/asf/syncope.git
commit 25dfcc05994b11fe4b33cb8458b2bd57cd93e4d9
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Mon Dec 3 13:18:36 2018 +0100
[SYNCOPE-1400] Adding support for MySQL 8 via OpenJPA 3.0.1 + [SYNCOPE-1401] Adding support for MySQL with JSON type
---
core/persistence-jpa-json/pom.xml | 129 ++++++---
...AJSONAnyDAO.java => AbstractJPAJSONAnyDAO.java} | 81 ++----
.../jpa/dao/AbstractJPAJSONAnySearchDAO.java | 125 +++++++++
.../core/persistence/jpa/dao/MyJPAJSONAnyDAO.java | 120 ++++++++
...nySearchDAO.java => MyJPAJSONAnySearchDAO.java} | 131 ++-------
.../core/persistence/jpa/dao/PGJPAJSONAnyDAO.java | 305 ++-------------------
.../persistence/jpa/dao/PGJPAJSONAnySearchDAO.java | 110 +-------
.../jpa/entity/JPAJSONEntityFactory.java | 3 +-
.../jpa/entity/MyJPAJSONEntityFactory.java | 37 +++
.../main/resources/META-INF/spring-orm-myjson.xml | 137 +++++++++
.../resources/myjson}/domains/Master.properties | 10 +-
.../src/main/resources/myjson/indexes.xml | 58 ++++
.../main/resources/myjson/persistence.properties | 23 +-
.../src/main/resources/myjson/views.xml | 181 ++++++++++++
.../{pgjsonb => }/domains/MasterContent.xml | 0
.../core/persistence/jpa/dao/JPAAnySearchDAO.java | 4 +
.../main/resources/audit/audit_mysql_innodb.sql | 2 +-
.../core/persistence/jpa/inner/AnyTypeTest.java | 2 +
fit/core-reference/pom.xml | 168 +++++++++++-
.../{mysql => myjson}/domains/Master.properties | 10 +-
.../{mysql => myjson}/provisioning.properties | 2 +-
.../main/resources/mysql/domains/Master.properties | 8 +-
.../main/resources/mysql/provisioning.properties | 2 +-
pom.xml | 5 +-
24 files changed, 1035 insertions(+), 618 deletions(-)
diff --git a/core/persistence-jpa-json/pom.xml b/core/persistence-jpa-json/pom.xml
index dfd7bb2..0331a27 100644
--- a/core/persistence-jpa-json/pom.xml
+++ b/core/persistence-jpa-json/pom.xml
@@ -227,10 +227,6 @@ under the License.
<filtering>true</filtering>
</testResource>
<testResource>
- <directory>src/test/resources/pgjsonb</directory>
- <filtering>true</filtering>
- </testResource>
- <testResource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</testResource>
@@ -243,62 +239,119 @@ under the License.
</profile>
<profile>
- <id>sqlgen</id>
-
- <properties>
- <skipTests>true</skipTests>
- </properties>
+ <id>mysql</id>
+ <dependencies>
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <version>${jdbc.mysql.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
<build>
<defaultGoal>clean verify</defaultGoal>
<plugins>
<plugin>
- <groupId>org.apache.openjpa</groupId>
- <artifactId>openjpa-maven-plugin</artifactId>
- <inherited>true</inherited>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
- <id>sqlgen</id>
- <phase>process-classes</phase>
+ <id>add-test-source</id>
+ <phase>generate-test-sources</phase>
<goals>
- <goal>sql</goal>
+ <goal>add-test-source</goal>
</goals>
+ <configuration>
+ <sources>
+ <source>${basedir}/../persistence-jpa/src/test/java</source>
+ </sources>
+ </configuration>
</execution>
</executions>
- </plugin>
- </plugins>
- </build>
- </profile>
-
- <profile>
- <id>schemagen</id>
-
- <properties>
- <skipTests>true</skipTests>
- </properties>
+ </plugin>
- <build>
- <defaultGoal>clean verify</defaultGoal>
-
- <plugins>
<plugin>
- <groupId>org.apache.openjpa</groupId>
- <artifactId>openjpa-maven-plugin</artifactId>
- <inherited>true</inherited>
+ <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>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>io.fabric8</groupId>
+ <artifactId>docker-maven-plugin</artifactId>
+ <configuration>
+ <images>
+ <image>
+ <name>mysql/mysql-server:${docker.mysql.version}</name>
+ <run>
+ <cmd>--skip-log-bin --server-id=1</cmd>
+ <env>
+ <MYSQL_ROOT_PASSWORD>password</MYSQL_ROOT_PASSWORD>
+ <MYSQL_DATABASE>syncope</MYSQL_DATABASE>
+ <MYSQL_USER>syncope</MYSQL_USER>
+ <MYSQL_PASSWORD>syncope</MYSQL_PASSWORD>
+ </env>
+ <ports>
+ <port>3306:3306</port>
+ </ports>
+ <wait>
+ <log>MySQL init process done. Ready for start up.</log>
+ <time>30000</time>
+ </wait>
+ </run>
+ </image>
+ </images>
+ </configuration>
<executions>
<execution>
- <id>schemagen</id>
- <phase>process-classes</phase>
+ <id>start-mysql</id>
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>start</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>stop-mysql</id>
+ <phase>post-integration-test</phase>
<goals>
- <goal>schema</goal>
+ <goal>stop</goal>
+ <goal>remove</goal>
</goals>
</execution>
</executions>
- </plugin>
+ </plugin>
</plugins>
+
+ <testResources>
+ <testResource>
+ <directory>src/test/resources</directory>
+ <filtering>true</filtering>
+ </testResource>
+ <testResource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </testResource>
+ <testResource>
+ <directory>src/main/resources/myjson</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/dao/PGJPAJSONAnyDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnyDAO.java
similarity index 81%
copy from core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnyDAO.java
copy to core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnyDAO.java
index 94bb72a..f0bca9a 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/AbstractJPAJSONAnyDAO.java
@@ -20,40 +20,37 @@ package org.apache.syncope.core.persistence.jpa.dao;
import java.io.StringReader;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
-import java.util.StringJoiner;
import java.util.regex.Pattern;
import javax.persistence.Query;
import org.apache.commons.jexl3.parser.Parser;
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.AttrSchemaType;
import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.DuplicateException;
+import org.apache.syncope.core.persistence.api.dao.JPAJSONAnyDAO;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
import org.apache.syncope.core.persistence.api.entity.DerSchema;
-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.JSONPlainAttr;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.persistence.jpa.entity.AbstractEntity;
-import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
import org.apache.syncope.core.spring.security.AuthContextUtils;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
-import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
-import org.apache.syncope.core.persistence.api.dao.JPAJSONAnyDAO;
-@Repository
-public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJSONAnyDAO {
+abstract class AbstractJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJSONAnyDAO {
@Autowired
private PlainSchemaDAO plainSchemaDAO;
@@ -61,22 +58,19 @@ public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJ
@Autowired
private DerSchemaDAO derSchemaDAO;
- private String queryBegin(final String table) {
- return "SELECT DISTINCT id FROM " + table + " u,"
- + "jsonb_array_elements(u.plainAttrs) attrs,"
- + "jsonb_array_elements(COALESCE(attrs -> 'values', '[{}]'::jsonb)) attrValues ";
- }
+ protected abstract String queryBegin(String table);
- private String attrValueMatch(
- final AnyUtils anyUtils,
- final PlainSchema schema,
- final PlainAttrValue attrValue,
- final boolean ignoreCaseMatch) {
+ protected abstract String attrValueMatch(
+ AnyUtils anyUtils,
+ PlainSchema schema,
+ PlainAttrValue attrValue,
+ boolean ignoreCaseMatch);
+ protected Pair<String, Boolean> schemaInfo(final AttrSchemaType schemaType, final boolean ignoreCaseMatch) {
String key;
boolean lower = false;
- switch (schema.getType()) {
+ switch (schemaType) {
case Boolean:
key = "booleanValue";
break;
@@ -102,29 +96,10 @@ public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJ
key = "stringValue";
}
- if (lower) {
- return "attrs ->> 'schema' = ? "
- + "AND "
- + (lower ? "LOWER(" : "")
- + (schema.isUniqueConstraint() ? "attrs -> 'uniqueValue'" : "attrValues") + " ->> '" + key
- + "'" + (lower ? ")" : "")
- + " = "
- + (lower ? "LOWER(" : "")
- + "?"
- + (lower ? ")" : "");
- } else {
- PlainAttr<?> container = anyUtils.newPlainAttr();
- container.setSchema(schema);
- if (attrValue instanceof PlainAttrUniqueValue) {
- container.setUniqueValue((PlainAttrUniqueValue) attrValue);
- } else {
- ((JSONPlainAttr) container).add(attrValue);
- }
- return "plainAttrs @> '" + POJOHelper.serialize(Arrays.asList(container)) + "'::jsonb";
- }
+ return Pair.of(key, lower);
}
- private <A extends Any<?>> List<A> buildResult(final AnyUtils anyUtils, final List<Object> queryResult) {
+ protected <A extends Any<?>> List<A> buildResult(final AnyUtils anyUtils, final List<Object> queryResult) {
List<A> result = new ArrayList<>();
queryResult.forEach(anyKey -> {
A any = anyUtils.<A>dao().find(anyKey.toString());
@@ -210,6 +185,8 @@ public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJ
return attrValues;
}
+ protected abstract List<Object> findByDerAttrValue(String table, Map<String, List<Object>> clauses);
+
@SuppressWarnings("unchecked")
@Transactional(readOnly = true)
@Override
@@ -272,7 +249,7 @@ public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJ
return Collections.emptyList();
}
- StringJoiner clauses = new StringJoiner(" AND id IN ");
+ Map<String, List<Object>> clauses = new LinkedHashMap<>();
// builder to build the clauses
StringBuilder bld = new StringBuilder();
@@ -280,8 +257,6 @@ public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJ
// Contains used identifiers in order to avoid replications
Set<String> used = new HashSet<>();
- List<Object> queryParams = new ArrayList<>();
-
// Create several clauses: one for eanch identifiers
for (int i = 0; i < identifiers.size(); i++) {
if (!used.contains(identifiers.get(i))) {
@@ -306,25 +281,21 @@ public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJ
append("WHERE ").
append(attrValueMatch(anyUtils, schema, attrValue, ignoreCaseMatch)).
append(')');
- queryParams.add(schema.getKey());
- queryParams.add(attrValues.get(i));
used.add(identifiers.get(i));
- clauses.add(bld.toString());
+ List<Object> queryParams = new ArrayList<>();
+ queryParams.add(schema.getKey());
+ queryParams.add(attrValues.get(i));
+
+ clauses.put(bld.toString(), queryParams);
}
}
}
LOG.debug("Generated where clauses {}", clauses);
- Query query = entityManager().createNativeQuery(
- "SELECT DISTINCT id FROM " + table + " u WHERE id IN " + clauses.toString());
- for (int i = 0; i < queryParams.size(); i++) {
- query.setParameter(i + 1, queryParams.get(i));
- }
-
- return buildResult(anyUtils, query.getResultList());
+ return buildResult(anyUtils, findByDerAttrValue(table, clauses));
}
@Transactional
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnySearchDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnySearchDAO.java
new file mode 100644
index 0000000..693d791
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnySearchDAO.java
@@ -0,0 +1,125 @@
+/*
+ * 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.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.search.AttributeCond;
+
+abstract class AbstractJPAJSONAnySearchDAO extends JPAAnySearchDAO {
+
+ @Override
+ SearchSupport buildSearchSupport(final AnyTypeKind kind) {
+ return new SearchSupport(kind);
+ }
+
+ @Override
+ protected void processOBS(final SearchSupport svs, final OrderBySupport obs, final StringBuilder where) {
+ obs.views.forEach(searchView -> {
+ where.append(',').
+ append(searchView.name).
+ append(' ').append(searchView.alias);
+ });
+ }
+
+ protected Pair<String, Boolean> schemaInfo(final AttrSchemaType schemaType, final AttributeCond.Type condType) {
+ String key;
+ boolean lower = false;
+ switch (schemaType) {
+ case Boolean:
+ key = "booleanValue";
+ break;
+
+ case Date:
+ key = "dateValue";
+ break;
+
+ case Double:
+ key = "doubleValue";
+ break;
+
+ case Long:
+ key = "longValue";
+ break;
+
+ case Binary:
+ key = "binaryValue";
+ break;
+
+ default:
+ lower = condType == AttributeCond.Type.IEQ || condType == AttributeCond.Type.ILIKE;
+ key = "stringValue";
+ }
+
+ return Pair.of(key, lower);
+ }
+
+ protected void appendOp(final StringBuilder query, final AttributeCond.Type condType, final boolean not) {
+ switch (condType) {
+ 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('=');
+ }
+ }
+}
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
new file mode 100644
index 0000000..e15e690
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnyDAO.java
@@ -0,0 +1,120 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.persistence.Query;
+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.entity.AnyUtils;
+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;
+import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
+
+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 + " ";
+ }
+
+ @Override
+ protected String attrValueMatch(
+ final AnyUtils anyUtils,
+ final PlainSchema schema,
+ final PlainAttrValue attrValue,
+ final boolean ignoreCaseMatch) {
+
+ Pair<String, Boolean> schemaInfo = schemaInfo(schema.getType(), ignoreCaseMatch);
+ if (schemaInfo.getRight()) {
+ return "plainSchema = ? "
+ + "AND "
+ + (schemaInfo.getRight() ? "LOWER(" : "")
+ + (schema.isUniqueConstraint()
+ ? "attrUniqueValue ->> '$." + schemaInfo.getLeft() + "'"
+ : schemaInfo.getLeft())
+ + (schemaInfo.getRight() ? ")" : "")
+ + " = "
+ + (schemaInfo.getRight() ? "LOWER(" : "")
+ + "?"
+ + (schemaInfo.getRight() ? ")" : "");
+ } else {
+ PlainAttr<?> container = anyUtils.newPlainAttr();
+ container.setSchema(schema);
+ if (attrValue instanceof PlainAttrUniqueValue) {
+ container.setUniqueValue((PlainAttrUniqueValue) attrValue);
+ } else {
+ ((JSONPlainAttr) container).add(attrValue);
+ }
+ return "JSON_CONTAINS(plainAttrs, '" + POJOHelper.serialize(Arrays.asList(container)) + "')";
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This method is a workaround for a bug experienced with MySQL 8.0.13, where the correct implementation (as shown
+ * in PGJPAJSONAnyDAO.findByDerAttrValue(String, Map<String, List<Object>>)) generates a core dump.
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ protected List<Object> findByDerAttrValue(
+ final String table,
+ final Map<String, List<Object>> clauses) {
+
+ if (clauses.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ Set<Object> result = new HashSet<>();
+ AtomicReference<Boolean> first = new AtomicReference<>(Boolean.TRUE);
+ clauses.forEach((clause, parameters) -> {
+ Query query = entityManager().createNativeQuery(StringUtils.replaceIgnoreCase(clause, "DISTINCT", ""));
+ for (int i = 0; i < parameters.size(); i++) {
+ query.setParameter(i + 1, parameters.get(i));
+ }
+
+ Set<Object> local = new HashSet<>(query.getResultList());
+ if (first.get()) {
+ result.addAll(local);
+ first.set(Boolean.FALSE);
+ } else {
+ result.retainAll(local);
+ }
+ });
+
+ return new ArrayList<>(result);
+ }
+}
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/MyJPAJSONAnySearchDAO.java
similarity index 55%
copy from core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
copy to core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
index f240705..4707372 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/MyJPAJSONAnySearchDAO.java
@@ -21,7 +21,6 @@ package org.apache.syncope.core.persistence.jpa.dao;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
@@ -32,21 +31,7 @@ import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
-public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
-
- @Override
- SearchSupport buildSearchSupport(final AnyTypeKind kind) {
- return new SearchSupport(kind);
- }
-
- @Override
- protected void processOBS(final SearchSupport svs, final OrderBySupport obs, final StringBuilder where) {
- obs.views.forEach(searchView -> {
- where.append(',').
- append(searchView.name).
- append(' ').append(searchView.alias);
- });
- }
+public class MyJPAJSONAnySearchDAO extends AbstractJPAJSONAnySearchDAO {
@Override
protected void parseOrderByForPlainSchema(
@@ -62,8 +47,10 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
obs.views.add(svs.field());
- item.select = svs.field().alias + ".attrValues ->> '" + fieldName + "' AS " + fieldName;
- item.where = "attrs ->> 'schema' = '" + fieldName + "'";
+ item.select = svs.field().alias + "."
+ + (schema.isUniqueConstraint() ? "attrUniqueValue" : svs.fieldName(schema.getType()))
+ + " AS " + fieldName;
+ item.where = "plainSchema = '" + fieldName + "'";
item.orderBy = fieldName + " " + clause.getDirection().name();
}
@@ -76,33 +63,7 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
final boolean not,
final List<Object> parameters) {
- String key;
- boolean lower = false;
- switch (schema.getType()) {
- case Boolean:
- key = "booleanValue";
- break;
-
- case Date:
- key = "dateValue";
- break;
-
- case Double:
- key = "doubleValue";
- break;
-
- case Long:
- key = "longValue";
- break;
-
- case Binary:
- key = "binaryValue";
- break;
-
- default:
- lower = cond.getType() == AttributeCond.Type.IEQ || cond.getType() == AttributeCond.Type.ILIKE;
- key = "stringValue";
- }
+ Pair<String, Boolean> schemaInfo = schemaInfo(schema.getType(), cond.getType());
if (!not && cond.getType() == AttributeCond.Type.EQ) {
PlainAttr<?> container = anyUtils.newPlainAttr();
@@ -113,71 +74,23 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
((JSONPlainAttr) container).add(attrValue);
}
- query.append("plainAttrs @> '").
+ query.append("JSON_CONTAINS(plainAttrs, '").
append(POJOHelper.serialize(Arrays.asList(container))).
- append("'::jsonb");
+ append("')");
} else {
- query.append("attrs ->> 'schema' = ?").append(setParameter(parameters, cond.getSchema())).
+ query.append("plainSchema = ?").append(setParameter(parameters, cond.getSchema())).
append(" AND ").
- append(lower ? "LOWER(" : "").
+ append(schemaInfo.getRight() ? "LOWER(" : "").
append(schema.isUniqueConstraint()
- ? "attrs -> 'uniqueValue'" : "attrValues").
- append(" ->> '").append(key).append("'").
- 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('=');
- }
+ ? "attrUniqueValue ->> '$." + schemaInfo.getLeft() + "'"
+ : schemaInfo.getLeft()).
+ append(schemaInfo.getRight() ? ")" : "");
+
+ appendOp(query, cond.getType(), not);
- query.append(lower ? "LOWER(" : "").
+ query.append(schemaInfo.getRight() ? "LOWER(" : "").
append("?").append(setParameter(parameters, cond.getExpression())).
- append(lower ? ")" : "");
+ append(schemaInfo.getRight() ? ")" : "");
}
}
@@ -208,17 +121,15 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
append(svs.field().name).append(" WHERE ");
switch (cond.getType()) {
case ISNOTNULL:
- query.append("plainAttrs @> '[{\"schema\":\"").
+ query.append("JSON_SEARCH(plainAttrs, 'one', '").
append(checked.getLeft().getKey()).
- append("\"}]'::jsonb");
+ append("', NULL, '$[*].schema') IS NOT NULL");
break;
case ISNULL:
- query.append("any_id NOT IN (").
- append("SELECT any_id FROM ").append(svs.field().name).
- append(" WHERE plainAttrs @> '[{\"schema\":\"").
+ query.append("JSON_SEARCH(plainAttrs, 'one', '").
append(checked.getLeft().getKey()).
- append("\"}]'::jsonb)");
+ append("', NULL, '$[*].schema') IS NULL");
break;
default:
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 94bb72a..ed1664b 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
@@ -18,100 +18,49 @@
*/
package org.apache.syncope.core.persistence.jpa.dao;
-import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
+import java.util.Map;
import java.util.StringJoiner;
-import java.util.regex.Pattern;
import javax.persistence.Query;
-import org.apache.commons.jexl3.parser.Parser;
-import org.apache.commons.jexl3.parser.ParserConstants;
-import org.apache.commons.jexl3.parser.Token;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
-import org.apache.syncope.core.persistence.api.dao.DuplicateException;
-import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
-import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
-import org.apache.syncope.core.persistence.api.entity.DerSchema;
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.persistence.jpa.entity.AbstractEntity;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
-import org.apache.syncope.core.spring.security.AuthContextUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
-import org.apache.syncope.core.persistence.api.dao.JPAJSONAnyDAO;
-@Repository
-public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJSONAnyDAO {
+public class PGJPAJSONAnyDAO extends AbstractJPAJSONAnyDAO {
- @Autowired
- private PlainSchemaDAO plainSchemaDAO;
-
- @Autowired
- private DerSchemaDAO derSchemaDAO;
-
- private String queryBegin(final String table) {
+ @Override
+ protected String queryBegin(final String table) {
return "SELECT DISTINCT id FROM " + table + " u,"
+ "jsonb_array_elements(u.plainAttrs) attrs,"
+ "jsonb_array_elements(COALESCE(attrs -> 'values', '[{}]'::jsonb)) attrValues ";
}
- private String attrValueMatch(
+ @Override
+ protected String attrValueMatch(
final AnyUtils anyUtils,
final PlainSchema schema,
final PlainAttrValue attrValue,
final boolean ignoreCaseMatch) {
- String key;
- boolean lower = false;
-
- switch (schema.getType()) {
- case Boolean:
- key = "booleanValue";
- break;
-
- case Date:
- key = "dateValue";
- break;
-
- case Double:
- key = "doubleValue";
- break;
-
- case Long:
- key = "longValue";
- break;
-
- case Binary:
- key = "binaryValue";
- break;
-
- default:
- lower = ignoreCaseMatch;
- key = "stringValue";
- }
-
- if (lower) {
+ Pair<String, Boolean> schemaInfo = schemaInfo(schema.getType(), ignoreCaseMatch);
+ if (schemaInfo.getRight()) {
return "attrs ->> 'schema' = ? "
+ "AND "
- + (lower ? "LOWER(" : "")
- + (schema.isUniqueConstraint() ? "attrs -> 'uniqueValue'" : "attrValues") + " ->> '" + key
- + "'" + (lower ? ")" : "")
+ + (schemaInfo.getRight() ? "LOWER(" : "")
+ + (schema.isUniqueConstraint() ? "attrs -> 'uniqueValue'" : "attrValues")
+ + " ->> '" + schemaInfo.getLeft()
+ + "'" + (schemaInfo.getRight() ? ")" : "")
+ " = "
- + (lower ? "LOWER(" : "")
+ + (schemaInfo.getRight() ? "LOWER(" : "")
+ "?"
- + (lower ? ")" : "");
+ + (schemaInfo.getRight() ? ")" : "");
} else {
PlainAttr<?> container = anyUtils.newPlainAttr();
container.setSchema(schema);
@@ -124,232 +73,26 @@ public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJ
}
}
- private <A extends Any<?>> List<A> buildResult(final AnyUtils anyUtils, final List<Object> queryResult) {
- List<A> result = new ArrayList<>();
- queryResult.forEach(anyKey -> {
- A any = anyUtils.<A>dao().find(anyKey.toString());
- if (any == null) {
- LOG.error("Could not find any for key {}", anyKey);
- } else {
- result.add(any);
- }
- });
- return result;
- }
-
- @SuppressWarnings("unchecked")
- @Transactional(readOnly = true)
@Override
- public <A extends Any<?>> List<A> findByPlainAttrValue(
- final String table,
- final AnyUtils anyUtils,
- final String schemaKey,
- final PlainAttrValue attrValue,
- final boolean ignoreCaseMatch) {
-
- PlainSchema schema = plainSchemaDAO.find(schemaKey);
- if (schema == null) {
- LOG.error("Invalid schema '{}'", schemaKey);
- return Collections.<A>emptyList();
- }
-
- Query query = entityManager().createNativeQuery(
- queryBegin(table)
- + "WHERE " + attrValueMatch(anyUtils, schema, attrValue, ignoreCaseMatch));
- query.setParameter(1, schemaKey);
- query.setParameter(2, attrValue.getValue());
-
- return buildResult(anyUtils, query.getResultList());
- }
-
- @Transactional(readOnly = true)
- @Override
- public <A extends Any<?>> A findByPlainAttrUniqueValue(
- final String table,
- final AnyUtils anyUtils,
- final String schemaKey,
- final PlainAttrValue attrUniqueValue,
- final boolean ignoreCaseMatch) {
-
- PlainSchema schema = plainSchemaDAO.find(schemaKey);
- if (schema == null) {
- LOG.error("Invalid schema '{}'", schemaKey);
- return null;
- }
- if (!schema.isUniqueConstraint()) {
- LOG.error("This schema has not unique constraint: '{}'", schemaKey);
- return null;
- }
-
- List<A> result = findByPlainAttrValue(table, anyUtils, schemaKey, attrUniqueValue, ignoreCaseMatch);
- return result.isEmpty()
- ? null
- : result.get(0);
- }
-
- /**
- * Split an attribute value recurring on provided literals/tokens.
- *
- * @param attrValue value to be split
- * @param literals literals/tokens
- * @return split value
- */
- private List<String> split(final String attrValue, final List<String> literals) {
- final List<String> attrValues = new ArrayList<>();
-
- if (literals.isEmpty()) {
- attrValues.add(attrValue);
- } else {
- for (String token : attrValue.split(Pattern.quote(literals.get(0)))) {
- if (!token.isEmpty()) {
- attrValues.addAll(split(token, literals.subList(1, literals.size())));
- }
- }
- }
-
- return attrValues;
- }
-
@SuppressWarnings("unchecked")
- @Transactional(readOnly = true)
- @Override
- public <A extends Any<?>> List<A> findByDerAttrValue(
+ protected List<Object> findByDerAttrValue(
final String table,
- final AnyUtils anyUtils,
- final String schemaKey,
- final String value,
- final boolean ignoreCaseMatch) {
-
- DerSchema derSchema = derSchemaDAO.find(schemaKey);
- if (derSchema == null) {
- LOG.error("Invalid schema '{}'", schemaKey);
- return Collections.<A>emptyList();
- }
-
- Parser parser = new Parser(new StringReader(derSchema.getExpression()));
-
- // Schema keys
- List<String> identifiers = new ArrayList<>();
-
- // Literals
- List<String> literals = new ArrayList<>();
-
- // Get schema keys and literals
- for (Token token = parser.getNextToken(); token != null && StringUtils.isNotBlank(token.toString());
- token = parser.getNextToken()) {
-
- if (token.kind == ParserConstants.STRING_LITERAL) {
- literals.add(token.toString().substring(1, token.toString().length() - 1));
- }
-
- if (token.kind == ParserConstants.IDENTIFIER) {
- identifiers.add(token.toString());
- }
- }
-
- // Sort literals in order to process later literals included into others
- Collections.sort(literals, (l1, l2) -> {
- if (l1 == null && l2 == null) {
- return 0;
- } else if (l1 != null && l2 == null) {
- return -1;
- } else if (l1 == null && l2 != null) {
- return 1;
- } else if (l1.length() == l2.length()) {
- return 0;
- } else if (l1.length() > l2.length()) {
- return -1;
- } else {
- return 1;
- }
- });
-
- // Split value on provided literals
- List<String> attrValues = split(value, literals);
-
- if (attrValues.size() != identifiers.size()) {
- LOG.error("Ambiguous JEXL expression resolution: literals and values have different size");
- return Collections.emptyList();
- }
-
- StringJoiner clauses = new StringJoiner(" AND id IN ");
-
- // builder to build the clauses
- StringBuilder bld = new StringBuilder();
-
- // Contains used identifiers in order to avoid replications
- Set<String> used = new HashSet<>();
+ final Map<String, List<Object>> clauses) {
+ StringJoiner actualClauses = new StringJoiner(" AND id IN ");
List<Object> queryParams = new ArrayList<>();
- // Create several clauses: one for eanch identifiers
- for (int i = 0; i < identifiers.size(); i++) {
- if (!used.contains(identifiers.get(i))) {
- // verify schema existence and get schema type
- PlainSchema schema = plainSchemaDAO.find(identifiers.get(i));
- if (schema == null) {
- LOG.error("Invalid schema '{}', ignoring", identifiers.get(i));
- } else {
- // clear builder
- bld.delete(0, bld.length());
-
- PlainAttrValue attrValue;
- if (schema.isUniqueConstraint()) {
- attrValue = anyUtils.newPlainAttrUniqueValue();
- } else {
- attrValue = anyUtils.newPlainAttrValue();
- }
- attrValue.setStringValue(attrValues.get(i));
-
- bld.append('(').
- append(queryBegin(table)).
- append("WHERE ").
- append(attrValueMatch(anyUtils, schema, attrValue, ignoreCaseMatch)).
- append(')');
- queryParams.add(schema.getKey());
- queryParams.add(attrValues.get(i));
-
- used.add(identifiers.get(i));
-
- clauses.add(bld.toString());
- }
- }
- }
-
- LOG.debug("Generated where clauses {}", clauses);
+ clauses.forEach((clause, parameters) -> {
+ actualClauses.add(clause);
+ queryParams.addAll(parameters);
+ });
Query query = entityManager().createNativeQuery(
- "SELECT DISTINCT id FROM " + table + " u WHERE id IN " + clauses.toString());
+ "SELECT DISTINCT id FROM " + table + " u WHERE id IN " + actualClauses.toString());
for (int i = 0; i < queryParams.size(); i++) {
query.setParameter(i + 1, queryParams.get(i));
}
- return buildResult(anyUtils, query.getResultList());
- }
-
- @Transactional
- @Override
- public <A extends Any<?>> void checkBeforeSave(final String table, final AnyUtils anyUtils, final A any) {
- // check UNIQUE constraints
- any.getPlainAttrs().stream().
- filter(attr -> attr.getUniqueValue() != null).
- map(JSONPlainAttr.class::cast).
- forEach(attr -> {
- String schemaKey = attr.getSchemaKey();
- List<A> others = findByPlainAttrValue(table, anyUtils, schemaKey, attr.getUniqueValue(), false);
- if (others.isEmpty() || (others.size() == 1 && others.get(0).getKey().equals(any.getKey()))) {
- LOG.debug("No duplicate value found for {}", attr.getUniqueValue().getValueAsString());
- } else {
- throw new DuplicateException(
- "Value " + attr.getUniqueValue().getValueAsString() + " existing for " + schemaKey);
- }
- });
-
- // update sysInfo - as org.apache.syncope.core.persistence.jpa.entity.PlainAttrListener is not invoked
- Date now = new Date();
- String username = AuthContextUtils.getUsername();
- LOG.debug("Set last change date '{}' and modifier '{}' for '{}'", now, username, any);
- any.setLastModifier(username);
- any.setLastChangeDate(now);
+ return query.getResultList();
}
}
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 f240705..399573a 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
@@ -21,7 +21,6 @@ package org.apache.syncope.core.persistence.jpa.dao;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
@@ -32,21 +31,7 @@ import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
-public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
-
- @Override
- SearchSupport buildSearchSupport(final AnyTypeKind kind) {
- return new SearchSupport(kind);
- }
-
- @Override
- protected void processOBS(final SearchSupport svs, final OrderBySupport obs, final StringBuilder where) {
- obs.views.forEach(searchView -> {
- where.append(',').
- append(searchView.name).
- append(' ').append(searchView.alias);
- });
- }
+public class PGJPAJSONAnySearchDAO extends AbstractJPAJSONAnySearchDAO {
@Override
protected void parseOrderByForPlainSchema(
@@ -76,33 +61,7 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
final boolean not,
final List<Object> parameters) {
- String key;
- boolean lower = false;
- switch (schema.getType()) {
- case Boolean:
- key = "booleanValue";
- break;
-
- case Date:
- key = "dateValue";
- break;
-
- case Double:
- key = "doubleValue";
- break;
-
- case Long:
- key = "longValue";
- break;
-
- case Binary:
- key = "binaryValue";
- break;
-
- default:
- lower = cond.getType() == AttributeCond.Type.IEQ || cond.getType() == AttributeCond.Type.ILIKE;
- key = "stringValue";
- }
+ Pair<String, Boolean> schemaInfo = schemaInfo(schema.getType(), cond.getType());
if (!not && cond.getType() == AttributeCond.Type.EQ) {
PlainAttr<?> container = anyUtils.newPlainAttr();
@@ -119,65 +78,16 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
} else {
query.append("attrs ->> 'schema' = ?").append(setParameter(parameters, cond.getSchema())).
append(" AND ").
- append(lower ? "LOWER(" : "").
- append(schema.isUniqueConstraint()
- ? "attrs -> 'uniqueValue'" : "attrValues").
- append(" ->> '").append(key).append("'").
- 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('=');
- }
+ append(schemaInfo.getRight() ? "LOWER(" : "").
+ append(schema.isUniqueConstraint() ? "attrs -> 'uniqueValue'" : "attrValues").
+ append(" ->> '").append(schemaInfo.getLeft()).append("'").
+ append(schemaInfo.getRight() ? ")" : "");
+
+ appendOp(query, cond.getType(), not);
- query.append(lower ? "LOWER(" : "").
+ query.append(schemaInfo.getRight() ? "LOWER(" : "").
append("?").append(setParameter(parameters, cond.getExpression())).
- append(lower ? ")" : "");
+ append(schemaInfo.getRight() ? ")" : "");
}
}
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAJSONEntityFactory.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAJSONEntityFactory.java
index bcd046d..a27e5e3 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAJSONEntityFactory.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAJSONEntityFactory.java
@@ -140,6 +140,7 @@ public abstract class JPAJSONEntityFactory extends JPAEntityFactory implements I
@Override
public void afterPropertiesSet() throws Exception {
- beanFactory.createBean(jpaJSONAnyDAOClass(), AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+ beanFactory.registerSingleton("jpaJSONAnyDAO",
+ beanFactory.createBean(jpaJSONAnyDAOClass(), AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false));
}
}
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/MyJPAJSONEntityFactory.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/MyJPAJSONEntityFactory.java
new file mode 100644
index 0000000..ca17f7b
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/MyJPAJSONEntityFactory.java
@@ -0,0 +1,37 @@
+/*
+ * 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.api.dao.JPAJSONAnyDAO;
+import org.apache.syncope.core.persistence.jpa.dao.MyJPAJSONAnyDAO;
+import org.apache.syncope.core.persistence.jpa.dao.MyJPAJSONAnySearchDAO;
+
+public class MyJPAJSONEntityFactory extends JPAJSONEntityFactory {
+
+ @Override
+ public Class<? extends AnySearchDAO> anySearchDAOClass() {
+ return MyJPAJSONAnySearchDAO.class;
+ }
+
+ @Override
+ protected Class<? extends JPAJSONAnyDAO> jpaJSONAnyDAOClass() {
+ return MyJPAJSONAnyDAO.class;
+ }
+}
diff --git a/core/persistence-jpa-json/src/main/resources/META-INF/spring-orm-myjson.xml b/core/persistence-jpa-json/src/main/resources/META-INF/spring-orm-myjson.xml
new file mode 100644
index 0000000..1c397a0
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/resources/META-INF/spring-orm-myjson.xml
@@ -0,0 +1,137 @@
+<?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="json"/>
+ <lob/>
+ </basic>
+ </attributes>
+ </entity>
+
+ <entity class="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup">
+ <attributes>
+ <basic name="plainAttrs">
+ <column column-definition="json"/>
+ <lob/>
+ </basic>
+ </attributes>
+ </entity>
+
+ <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONUser">
+ <attributes>
+ <basic name="plainAttrs">
+ <column column-definition="json"/>
+ <lob/>
+ </basic>
+ </attributes>
+ </entity>
+
+ <entity class="org.apache.syncope.core.persistence.jpa.entity.conf.JPAJSONConf">
+ <attributes>
+ <basic name="plainAttrs">
+ <column column-definition="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/fit/core-reference/src/main/resources/mysql/domains/Master.properties b/core/persistence-jpa-json/src/main/resources/myjson/domains/Master.properties
similarity index 76%
copy from fit/core-reference/src/main/resources/mysql/domains/Master.properties
copy to core/persistence-jpa-json/src/main/resources/myjson/domains/Master.properties
index ce09eec..d945b5a 100644
--- a/fit/core-reference/src/main/resources/mysql/domains/Master.properties
+++ b/core/persistence-jpa-json/src/main/resources/myjson/domains/Master.properties
@@ -14,15 +14,15 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-Master.driverClassName=com.mysql.jdbc.Driver
-Master.url=jdbc:mysql://localhost:3306/syncope?characterEncoding=UTF-8&relaxAutoCommit=true
+Master.driverClassName=com.mysql.cj.jdbc.Driver
+Master.url=jdbc:mysql://localhost:3306/syncope?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8
Master.schema=
Master.username=syncope
Master.password=syncope
-Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB)
-Master.orm=META-INF/spring-orm.xml
+Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB,timestampTypeName=DATETIME(3))
+Master.orm=META-INF/spring-orm-myjson.xml
Master.pool.maxActive=10
Master.pool.minIdle=2
-Master.audit.sql=audit.sql
+Master.audit.sql=audit_mysql_innodb.sql
diff --git a/core/persistence-jpa-json/src/main/resources/myjson/indexes.xml b/core/persistence-jpa-json/src/main/resources/myjson/indexes.xml
new file mode 100644
index 0000000..b16004d
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/resources/myjson/indexes.xml
@@ -0,0 +1,58 @@
+<?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>
+
+ <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="CPlainAttrValue_stringvalueIndex">CREATE INDEX CAttrValue_stringvalueIndex ON CPlainAttrValue(stringvalue)</entry>
+ <entry key="CPlainAttrValue_datevalueIndex">CREATE INDEX CAttrValue_datevalueIndex ON CPlainAttrValue(datevalue)</entry>
+ <entry key="CPlainAttrValue_longvalueIndex">CREATE INDEX CAttrValue_longvalueIndex ON CPlainAttrValue(longvalue)</entry>
+ <entry key="CPlainAttrValue_doublevalueIndex">CREATE INDEX CAttrValue_doublevalueIndex ON CPlainAttrValue(doublevalue)</entry>
+ <entry key="CPlainAttrValue_booleanvalueIndex">CREATE INDEX CAttrValue_booleanvalueIndex ON CPlainAttrValue(booleanvalue)</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="CPlainAttrValue_attrIndex">CREATE INDEX CPlainAttrValue_attrIndex on CPlainAttrValue(attribute_id)</entry>
+ <entry key="CPAttrUniqueValue_attrIndex">CREATE INDEX CPAttrUniqueValue_attrIndex on CPlainAttrUniqueValue(attribute_id)</entry>
+
+ <entry key="CPlainAttr_owner_Index">CREATE INDEX CPlainAttr_owner_Index on CPlainAttr(owner_id)</entry>
+ <entry key="CPlainAttr_schema_Index">CREATE INDEX CPlainAttr_schema_Index on CPlainAttr(schema_id)</entry>
+
+ <entry key="Task_executedIndex">CREATE INDEX Task_executedIndex ON Task(executed)</entry>
+</properties>
diff --git a/fit/core-reference/src/main/resources/mysql/domains/Master.properties b/core/persistence-jpa-json/src/main/resources/myjson/persistence.properties
similarity index 50%
copy from fit/core-reference/src/main/resources/mysql/domains/Master.properties
copy to core/persistence-jpa-json/src/main/resources/myjson/persistence.properties
index ce09eec..31a2dd8 100644
--- a/fit/core-reference/src/main/resources/mysql/domains/Master.properties
+++ b/core/persistence-jpa-json/src/main/resources/myjson/persistence.properties
@@ -14,15 +14,14 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-Master.driverClassName=com.mysql.jdbc.Driver
-Master.url=jdbc:mysql://localhost:3306/syncope?characterEncoding=UTF-8&relaxAutoCommit=true
-Master.schema=
-Master.username=syncope
-Master.password=syncope
-Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB)
-Master.orm=META-INF/spring-orm.xml
-
-Master.pool.maxActive=10
-Master.pool.minIdle=2
-
-Master.audit.sql=audit.sql
+content.directory=${conf.directory}
+entity.factory=org.apache.syncope.core.persistence.jpa.entity.MyJPAJSONEntityFactory
+plainSchema.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONPlainSchemaDAO
+plainAttr.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONPlainAttrDAO
+plainAttrValue.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONPlainAttrValueDAO
+any.search.dao=org.apache.syncope.core.persistence.jpa.dao.MyJPAJSONAnySearchDAO
+user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONUserDAO
+group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONGroupDAO
+anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONAnyObjectDAO
+conf.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONConfDAO
+openjpa.RemoteCommitProvider=sjvm
diff --git a/core/persistence-jpa-json/src/main/resources/myjson/views.xml b/core/persistence-jpa-json/src/main/resources/myjson/views.xml
new file mode 100644
index 0000000..aa0e3c0
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/resources/myjson/views.xml
@@ -0,0 +1,181 @@
+<?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>
+
+ <entry key="UDynGroupMembers">
+ CREATE TABLE UDynGroupMembers(
+ any_id CHAR(36),
+ group_id CHAR(36),
+ UNIQUE(any_id, group_id))
+ </entry>
+ <entry key="ADynGroupMembers">
+ CREATE TABLE ADynGroupMembers(
+ anyType_id VARCHAR(255),
+ any_id CHAR(36),
+ group_id CHAR(36),
+ UNIQUE(anyType_id, any_id, group_id))
+ </entry>
+ <entry key="DynRoleMembers">
+ CREATE TABLE DynRoleMembers(
+ any_id CHAR(36),
+ role_id VARCHAR(255),
+ UNIQUE(any_id, role_id))
+ </entry>
+ <entry key="DynRealmMembers">
+ CREATE TABLE DynRealmMembers(
+ any_id CHAR(36),
+ dynRealm_id VARCHAR(255),
+ UNIQUE(any_id, dynRealm_id))
+ </entry>
+
+ <!-- user -->
+ <entry key="user_search">
+ 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 BIGINT(20) PATH '$.dateValue',
+ doubleValue DOUBLE PATH '$.doubleValue',
+ longValue BIGINT(20) PATH '$.longValue',
+ stringValue VARCHAR(255) PATH '$.stringValue'),
+ attrUniqueValue JSON PATH '$.uniqueValue')
+ ) AS attrs
+ </entry>
+ <entry key="user_search_urelationship">
+ CREATE VIEW user_search_urelationship AS
+
+ SELECT m.user_id AS any_id, m.anyObject_id AS right_any_id, m.type_id AS type
+ FROM URelationship m
+ </entry>
+ <entry key="user_search_umembership">
+ CREATE VIEW user_search_umembership AS
+
+ SELECT m.user_id AS any_id, g.id AS group_id, g.name AS group_name
+ FROM UMembership m, SyncopeGroup g
+ WHERE m.group_id = g.id
+ </entry>
+ <entry key="user_search_role">
+ CREATE VIEW user_search_role AS
+
+ SELECT ss.user_id AS any_id, ss.role_id AS role_id
+ FROM SyncopeUser_SyncopeRole ss
+ </entry>
+ <entry key="user_search_priv">
+ CREATE VIEW user_search_priv AS
+
+ SELECT ss.user_id AS any_id, sp.privilege_id AS privilege_id
+ FROM SyncopeUser_SyncopeRole ss, SyncopeRole_Privilege sp
+ WHERE ss.role_id = sp.role_id
+ </entry>
+ <entry key="user_search_dynpriv">
+ CREATE VIEW user_search_dynpriv AS
+
+ SELECT any_id, privilege_id
+ FROM DynRoleMembers drm, SyncopeRole_Privilege rp
+ WHERE drm.role_id = rp.role_id
+ </entry>
+ <entry key="user_search_resource">
+ CREATE VIEW user_search_resource AS
+
+ SELECT st.user_id AS any_id, st.resource_id AS resource_id
+ FROM SyncopeUser_ExternalResource st
+ </entry>
+ <entry key="user_search_group_res">
+ CREATE VIEW user_search_group_res AS
+
+ SELECT m.user_id AS any_id, st.resource_id AS resource_id
+ FROM UMembership m, SyncopeGroup r, SyncopeGroup_ExternalResource st
+ WHERE m.group_id = r.id AND st.group_id = r.id
+ </entry>
+
+ <!-- anyObject -->
+ <entry key="anyObject_search">
+ 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 BIGINT(20) PATH '$.dateValue',
+ doubleValue DOUBLE PATH '$.doubleValue',
+ longValue BIGINT(20) PATH '$.longValue',
+ stringValue VARCHAR(255) PATH '$.stringValue'),
+ attrUniqueValue JSON PATH '$.uniqueValue')
+ ) AS attrs
+ </entry>
+ <entry key="anyObject_search_arelationship">
+ CREATE VIEW anyObject_search_arelationship AS
+
+ SELECT m.left_anyObject_id AS any_id, m.right_anyObject_id AS right_any_id, m.type_id AS type
+ FROM ARelationship m
+ </entry>
+ <entry key="anyObject_search_amembership">
+ CREATE VIEW anyObject_search_amembership AS
+
+ SELECT m.anyObject_id AS any_id, g.id AS group_id, g.name AS group_name
+ FROM AMembership m, SyncopeGroup g
+ WHERE m.group_id = g.id
+ </entry>
+ <entry key="anyObject_search_resource">
+ CREATE VIEW anyObject_search_resource AS
+
+ SELECT st.anyObject_id AS any_id, st.resource_id AS resource_id
+ FROM AnyObject_ExternalResource st
+ </entry>
+ <entry key="anyObject_search_group_res">
+ CREATE VIEW anyObject_search_group_res AS
+
+ SELECT m.anyObject_id AS any_id, st.resource_id AS resource_id
+ FROM AMembership m, SyncopeGroup r, SyncopeGroup_ExternalResource st
+ WHERE m.group_id = r.id AND st.group_id = r.id
+ </entry>
+
+ <!-- group -->
+ <entry key="group_search">
+ 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 BIGINT(20) PATH '$.dateValue',
+ doubleValue DOUBLE PATH '$.doubleValue',
+ longValue BIGINT(20) PATH '$.longValue',
+ stringValue VARCHAR(255) PATH '$.stringValue'),
+ attrUniqueValue JSON PATH '$.uniqueValue')
+ ) AS attrs
+ </entry>
+ <entry key="group_search_resource">
+ CREATE VIEW group_search_resource AS
+
+ SELECT st.group_id AS any_id, st.resource_id AS resource_id
+ FROM SyncopeGroup_ExternalResource st
+ </entry>
+
+</properties>
diff --git a/core/persistence-jpa-json/src/test/resources/pgjsonb/domains/MasterContent.xml b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
similarity index 100%
rename from core/persistence-jpa-json/src/test/resources/pgjsonb/domains/MasterContent.xml
rename to core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
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 02e2535..fcf3bba 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
@@ -166,6 +166,8 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
// 1. get the query string from the search condition
StringBuilder queryString = getQuery(buildEffectiveCond(cond, filter.getRight()), parameters, svs);
+ LOG.debug("Query: {}, parameters: {}", queryString, parameters);
+
// 2. take into account realms and ordering
OrderBySupport obs = parseOrderBy(kind, svs, orderBy);
if (queryString.charAt(0) == '(') {
@@ -179,6 +181,8 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
append(filter.getLeft()).
append(buildOrderBy(obs));
+ LOG.debug("Query with auth and order by statements: {}, parameters: {}", queryString, parameters);
+
// 3. prepare the search query
Query query = entityManager().createNativeQuery(queryString.toString());
diff --git a/core/persistence-jpa/src/main/resources/audit/audit_mysql_innodb.sql b/core/persistence-jpa/src/main/resources/audit/audit_mysql_innodb.sql
index ff753fa..4d8426c 100644
--- a/core/persistence-jpa/src/main/resources/audit/audit_mysql_innodb.sql
+++ b/core/persistence-jpa/src/main/resources/audit/audit_mysql_innodb.sql
@@ -21,4 +21,4 @@ CREATE TABLE IF NOT EXISTS SYNCOPEAUDIT (
LOGGER VARCHAR(255) NOT NULL,
MESSAGE TEXT NOT NULL,
THROWABLE TEXT
-) ENGINE=InnoDB
+) ENGINE=InnoDB;
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyTypeTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyTypeTest.java
index 1db62d8..26b1da9 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyTypeTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyTypeTest.java
@@ -90,6 +90,7 @@ public class AnyTypeTest extends AbstractTest {
newType.setKey("new type");
newType.setKind(AnyTypeKind.USER);
anyTypeDAO.save(newType);
+ entityManager().flush();
});
}
@@ -100,6 +101,7 @@ public class AnyTypeTest extends AbstractTest {
newType.setKey("group");
newType.setKind(AnyTypeKind.ANY_OBJECT);
anyTypeDAO.save(newType);
+ entityManager().flush();
});
}
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index 85c992c..645dcca 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -724,7 +724,7 @@ under the License.
<filtering>true</filtering>
</resource>
<resource>
- <directory>${basedir}/../../core/persistence-jpa-json/src/test/resources/pgjsonb/domains</directory>
+ <directory>${basedir}/../../core/persistence-jpa-json/src/test/resources/domains</directory>
<targetPath>${project.build.directory}/classes/domains</targetPath>
<filtering>true</filtering>
</resource>
@@ -851,7 +851,165 @@ under the License.
</testResources>
</build>
</profile>
+
+ <profile>
+ <id>myjson-it</id>
+
+ <properties>
+ <jdbcdriver.groupId>mysql</jdbcdriver.groupId>
+ <jdbcdriver.artifactId>mysql-connector-java</jdbcdriver.artifactId>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.syncope.core</groupId>
+ <artifactId>syncope-core-persistence-jpa-json</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <version>${jdbc.mysql.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <defaultGoal>clean verify</defaultGoal>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <configuration>
+ <packagingExcludes>WEB-INF/classes/domains/Two*</packagingExcludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <inherited>true</inherited>
+ <executions>
+ <execution>
+ <id>remove-domain-Two</id>
+ <phase>prepare-package</phase>
+ <configuration>
+ <target>
+ <delete>
+ <fileset dir="${project.build.directory}/classes/domains" includes="Two*"/>
+ </delete>
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>io.fabric8</groupId>
+ <artifactId>docker-maven-plugin</artifactId>
+ <configuration>
+ <images>
+ <image>
+ <name>mysql/mysql-server:${docker.mysql.version}</name>
+ <run>
+ <cmd>--skip-log-bin --server-id=1</cmd>
+ <env>
+ <MYSQL_ROOT_PASSWORD>password</MYSQL_ROOT_PASSWORD>
+ <MYSQL_DATABASE>syncope</MYSQL_DATABASE>
+ <MYSQL_USER>syncope</MYSQL_USER>
+ <MYSQL_PASSWORD>syncope</MYSQL_PASSWORD>
+ </env>
+ <ports>
+ <port>3306:3306</port>
+ </ports>
+ <wait>
+ <log>MySQL init process done. Ready for start up.</log>
+ <time>30000</time>
+ </wait>
+ </run>
+ </image>
+ </images>
+ </configuration>
+ <executions>
+ <execution>
+ <id>start-mysql</id>
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>start</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>stop-mysql</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-maven2-plugin</artifactId>
+ <inherited>true</inherited>
+ <executions>
+ <execution>
+ <id>start-container</id>
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>start</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>stop-container</id>
+ <phase>post-integration-test</phase>
+ <goals>
+ <goal>stop</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ <excludes>
+ <exclude>provisioning.properties</exclude>
+ <exclude>indexes.xml</exclude>
+ <exclude>views.xml</exclude>
+ </excludes>
+ </resource>
+ <resource>
+ <directory>src/main/resources/myjson</directory>
+ <filtering>true</filtering>
+ </resource>
+ <resource>
+ <directory>${basedir}/../../core/persistence-jpa-json/src/test/resources/domains</directory>
+ <targetPath>${project.build.directory}/classes/domains</targetPath>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ <testResources>
+ <testResource>
+ <directory>${basedir}/../../core/persistence-jpa-json/src/main/resources/myjson</directory>
+ <includes>
+ <include>persistence.properties</include>
+ <include>indexes.xml</include>
+ <include>views.xml</include>
+ </includes>
+ </testResource>
+ </testResources>
+ </build>
+ </profile>
+
<profile>
<id>mysql-it</id>
@@ -879,9 +1037,11 @@ under the License.
<configuration>
<images>
<image>
- <name>mysql/mysql-server:5.7</name>
+ <name>mysql/mysql-server:${docker.mysql.version}</name>
<run>
+ <cmd>--skip-log-bin --server-id=1</cmd>
<env>
+ <MYSQL_ROOT_PASSWORD>password</MYSQL_ROOT_PASSWORD>
<MYSQL_DATABASE>syncope</MYSQL_DATABASE>
<MYSQL_USER>syncope</MYSQL_USER>
<MYSQL_PASSWORD>syncope</MYSQL_PASSWORD>
@@ -889,6 +1049,10 @@ under the License.
<ports>
<port>3306:3306</port>
</ports>
+ <wait>
+ <log>MySQL init process done. Ready for start up.</log>
+ <time>30000</time>
+ </wait>
</run>
</image>
</images>
diff --git a/fit/core-reference/src/main/resources/mysql/domains/Master.properties b/fit/core-reference/src/main/resources/myjson/domains/Master.properties
similarity index 76%
copy from fit/core-reference/src/main/resources/mysql/domains/Master.properties
copy to fit/core-reference/src/main/resources/myjson/domains/Master.properties
index ce09eec..d945b5a 100644
--- a/fit/core-reference/src/main/resources/mysql/domains/Master.properties
+++ b/fit/core-reference/src/main/resources/myjson/domains/Master.properties
@@ -14,15 +14,15 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-Master.driverClassName=com.mysql.jdbc.Driver
-Master.url=jdbc:mysql://localhost:3306/syncope?characterEncoding=UTF-8&relaxAutoCommit=true
+Master.driverClassName=com.mysql.cj.jdbc.Driver
+Master.url=jdbc:mysql://localhost:3306/syncope?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8
Master.schema=
Master.username=syncope
Master.password=syncope
-Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB)
-Master.orm=META-INF/spring-orm.xml
+Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB,timestampTypeName=DATETIME(3))
+Master.orm=META-INF/spring-orm-myjson.xml
Master.pool.maxActive=10
Master.pool.minIdle=2
-Master.audit.sql=audit.sql
+Master.audit.sql=audit_mysql_innodb.sql
diff --git a/fit/core-reference/src/main/resources/mysql/provisioning.properties b/fit/core-reference/src/main/resources/myjson/provisioning.properties
similarity index 97%
copy from fit/core-reference/src/main/resources/mysql/provisioning.properties
copy to fit/core-reference/src/main/resources/myjson/provisioning.properties
index 48f9ef6..3883cb5 100644
--- a/fit/core-reference/src/main/resources/mysql/provisioning.properties
+++ b/fit/core-reference/src/main/resources/myjson/provisioning.properties
@@ -27,6 +27,6 @@ anyObjectProvisioningManager=org.apache.syncope.core.provisioning.java.DefaultAn
virAttrCache=org.apache.syncope.core.provisioning.java.cache.MemoryVirAttrCache
quartz.jobstore=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
-quartz.sql=tables_mysql.sql
+quartz.sql=tables_mysql_innodb.sql
quartz.scheduler.idleWaitTime=5000
quartz.disableInstance=false
diff --git a/fit/core-reference/src/main/resources/mysql/domains/Master.properties b/fit/core-reference/src/main/resources/mysql/domains/Master.properties
index ce09eec..e36e370 100644
--- a/fit/core-reference/src/main/resources/mysql/domains/Master.properties
+++ b/fit/core-reference/src/main/resources/mysql/domains/Master.properties
@@ -14,15 +14,15 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-Master.driverClassName=com.mysql.jdbc.Driver
-Master.url=jdbc:mysql://localhost:3306/syncope?characterEncoding=UTF-8&relaxAutoCommit=true
+Master.driverClassName=com.mysql.cj.jdbc.Driver
+Master.url=jdbc:mysql://localhost:3306/syncope?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8
Master.schema=
Master.username=syncope
Master.password=syncope
-Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB)
+Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB,timestampTypeName=DATETIME(3))
Master.orm=META-INF/spring-orm.xml
Master.pool.maxActive=10
Master.pool.minIdle=2
-Master.audit.sql=audit.sql
+Master.audit.sql=audit_mysql_innodb.sql
diff --git a/fit/core-reference/src/main/resources/mysql/provisioning.properties b/fit/core-reference/src/main/resources/mysql/provisioning.properties
index 48f9ef6..3883cb5 100644
--- a/fit/core-reference/src/main/resources/mysql/provisioning.properties
+++ b/fit/core-reference/src/main/resources/mysql/provisioning.properties
@@ -27,6 +27,6 @@ anyObjectProvisioningManager=org.apache.syncope.core.provisioning.java.DefaultAn
virAttrCache=org.apache.syncope.core.provisioning.java.cache.MemoryVirAttrCache
quartz.jobstore=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
-quartz.sql=tables_mysql.sql
+quartz.sql=tables_mysql_innodb.sql
quartz.scheduler.idleWaitTime=5000
quartz.disableInstance=false
diff --git a/pom.xml b/pom.xml
index 25df74d..5293fff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -396,7 +396,7 @@ under the License.
<spring.version>5.1.3.RELEASE</spring.version>
<spring-security.version>5.1.2.RELEASE</spring-security.version>
- <openjpa.version>3.0.0</openjpa.version>
+ <openjpa.version>3.0.1-SNAPSHOT</openjpa.version>
<hikaricp.version>3.2.0</hikaricp.version>
<bval.version>1.1.2</bval.version>
@@ -518,10 +518,11 @@ under the License.
<protractor.version>5.4.0</protractor.version>
<docker.postgresql.version>11.1</docker.postgresql.version>
+ <docker.mysql.version>8.0</docker.mysql.version>
<docker.mariadb.version>10.4</docker.mariadb.version>
<jdbc.postgresql.version>42.2.5</jdbc.postgresql.version>
- <jdbc.mysql.version>5.1.47</jdbc.mysql.version>
+ <jdbc.mysql.version>8.0.13</jdbc.mysql.version>
<jdbc.mariadb.version>2.3.0</jdbc.mariadb.version>
<jdbc.mssql.version>6.4.0.jre</jdbc.mssql.version>