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 2020/02/05 17:17:10 UTC
[syncope] branch master updated (342d0b5 -> 0a5fd91)
This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git.
from 342d0b5 [SYNCOPE-1539] setRequired for AjaxPalettePanel (#165)
new b4ea617 Upgrading asciidoctorj-pdf
new 0a5fd91 [SYNCOPE-1540] Use JPA metamodel to guess the right case for column and table names
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../jpa/content/XMLContentExporter.java | 162 +++++++++++++++++++--
.../jpa/outer/XMLContentExporterTest.java | 12 +-
pom.xml | 2 +-
3 files changed, 161 insertions(+), 15 deletions(-)
[syncope] 01/02: Upgrading asciidoctorj-pdf
Posted by il...@apache.org.
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
commit b4ea6171116ce51e6c99a65a5c8b2aeed6c9adce
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Wed Feb 5 17:27:19 2020 +0100
Upgrading asciidoctorj-pdf
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index d0ccaec..1e05202 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2532,7 +2532,7 @@ under the License.
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-pdf</artifactId>
- <version>1.5.0-rc.2</version>
+ <version>1.5.0-rc.3</version>
</dependency>
</dependencies>
<configuration>
[syncope] 02/02: [SYNCOPE-1540] Use JPA metamodel to guess the
right case for column and table names
Posted by il...@apache.org.
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
commit 0a5fd9196e129e4ccb52603e5c74af1fa7c796ca
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Wed Feb 5 17:57:28 2020 +0100
[SYNCOPE-1540] Use JPA metamodel to guess the right case for column and table names
---
.../jpa/content/XMLContentExporter.java | 162 +++++++++++++++++++--
.../jpa/outer/XMLContentExporterTest.java | 12 +-
2 files changed, 160 insertions(+), 14 deletions(-)
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
index 4a279f5..8015088 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.persistence.jpa.content;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.sql.Blob;
import java.sql.Connection;
@@ -38,24 +39,38 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.JoinTable;
+import javax.persistence.Table;
+import javax.persistence.metamodel.Attribute;
+import javax.persistence.metamodel.EntityType;
+import javax.persistence.metamodel.PluralAttribute;
import javax.sql.DataSource;
-import javax.xml.bind.DatatypeConverter;
import javax.xml.XMLConstants;
+import javax.xml.bind.DatatypeConverter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
-
+import org.apache.commons.collections4.BidiMap;
+import org.apache.commons.collections4.bidimap.DualHashBidiMap;
import org.apache.commons.collections4.SetUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.core.provisioning.api.utils.FormatUtils;
-import org.apache.syncope.core.spring.ApplicationContextProvider;
import org.apache.syncope.core.persistence.api.content.ContentExporter;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.jpa.entity.JPAAccessToken;
@@ -76,8 +91,10 @@ import org.apache.syncope.core.persistence.jpa.entity.user.JPAURelationship;
import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceUtils;
+import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.stereotype.Component;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
@@ -238,11 +255,44 @@ public class XMLContentExporter implements ContentExporter {
return res;
}
+ private String columnName(final Supplier<Stream<Attribute<?, ?>>> attrs, final String columnName) {
+ String name = attrs.get().map(attr -> {
+ if (attr.getName().equalsIgnoreCase(columnName)) {
+ return attr.getName();
+ }
+
+ Field field = (Field) attr.getJavaMember();
+ Column column = field.getAnnotation(Column.class);
+ if (column != null && column.name().equalsIgnoreCase(columnName)) {
+ return column.name();
+ }
+
+ return null;
+ }).filter(Objects::nonNull).findFirst().orElse(columnName);
+
+ if (StringUtils.endsWithIgnoreCase(name, "_ID")) {
+ String left = StringUtils.substringBefore(name, "_");
+ String prefix = attrs.get().filter(attr -> left.equalsIgnoreCase(attr.getName())).findFirst().
+ map(Attribute::getName).orElse(left);
+ name = prefix + "_id";
+ }
+
+ return name;
+ }
+
+ private boolean isTask(final String tableName) {
+ return "TASK".equalsIgnoreCase(tableName);
+ }
+
+ @SuppressWarnings("unchecked")
private void exportTable(
final TransformerHandler handler,
final Connection conn,
final String tableName,
- final String whereClause) throws SQLException, SAXException {
+ final String whereClause,
+ final BidiMap<String, EntityType<?>> entities,
+ final Set<EntityType<?>> taskEntities,
+ final Map<String, Pair<String, String>> relationTables) throws SQLException, SAXException {
LOG.debug("Export table {}", tableName);
@@ -290,6 +340,19 @@ public class XMLContentExporter implements ContentExporter {
List<Map<String, String>> rows = new ArrayList<>();
+ Optional<EntityType<?>> entity = entities.entrySet().stream().
+ filter(entry -> entry.getKey().equalsIgnoreCase(tableName)).
+ findFirst().
+ map(Map.Entry::getValue);
+
+ String outputTableName = entity.isPresent()
+ ? entities.getKey(entity.get())
+ : relationTables.keySet().stream().filter(key -> tableName.equalsIgnoreCase(key)).findFirst().
+ orElse(tableName);
+ if (isTask(tableName)) {
+ outputTableName = "Task";
+ }
+
rs = stmt.executeQuery();
while (rs.next()) {
Map<String, String> row = new HashMap<>();
@@ -305,8 +368,28 @@ public class XMLContentExporter implements ContentExporter {
if (value != null && (!COLUMNS_TO_BE_NULLIFIED.containsKey(tableName)
|| !COLUMNS_TO_BE_NULLIFIED.get(tableName).contains(columnName))) {
- row.put(columnName, value);
- LOG.debug("Add for table {}: {}=\"{}\"", tableName, columnName, value);
+ String name = columnName;
+ if (entity.isPresent()) {
+ name = columnName(
+ () -> (Stream<Attribute<?, ?>>) entity.get().getAttributes().stream(), columnName);
+ }
+
+ if (isTask(tableName)) {
+ name = columnName(
+ () -> taskEntities.stream().flatMap(e -> e.getAttributes().stream()), columnName);
+ }
+
+ if (relationTables.containsKey(outputTableName)) {
+ Pair<String, String> relationColumns = relationTables.get(outputTableName);
+ if (name.equalsIgnoreCase(relationColumns.getLeft())) {
+ name = relationColumns.getLeft();
+ } else if (name.equalsIgnoreCase(relationColumns.getRight())) {
+ name = relationColumns.getRight();
+ }
+ }
+
+ row.put(name, value);
+ LOG.debug("Add for table {}: {}=\"{}\"", outputTableName, name, value);
}
}
}
@@ -327,8 +410,8 @@ public class XMLContentExporter implements ContentExporter {
AttributesImpl attrs = new AttributesImpl();
row.forEach((key, value) -> attrs.addAttribute("", "", key, "CDATA", value));
- handler.startElement("", "", tableName, attrs);
- handler.endElement("", "", tableName);
+ handler.startElement("", "", outputTableName, attrs);
+ handler.endElement("", "", outputTableName);
}
} finally {
if (rs != null) {
@@ -348,6 +431,60 @@ public class XMLContentExporter implements ContentExporter {
}
}
+ private Set<EntityType<?>> taskEntities(final Set<EntityType<?>> entityTypes) {
+ return entityTypes.stream().filter(e -> e.getName().endsWith("Task")).collect(Collectors.toSet());
+ }
+
+ private BidiMap<String, EntityType<?>> entities(final Set<EntityType<?>> entityTypes) {
+ BidiMap<String, EntityType<?>> entities = new DualHashBidiMap<>();
+ entityTypes.forEach(entity -> {
+ Table table = entity.getBindableJavaType().getAnnotation(Table.class);
+ if (table != null) {
+ entities.put(table.name(), entity);
+ }
+ });
+
+ return entities;
+ }
+
+ private Map<String, Pair<String, String>> relationTables(final BidiMap<String, EntityType<?>> entities) {
+ Map<String, Pair<String, String>> relationTables = new HashMap<>();
+ entities.values().stream().forEach(e -> e.getAttributes().stream().
+ filter(a -> a.getPersistentAttributeType() != Attribute.PersistentAttributeType.BASIC).
+ forEach(a -> {
+ String attrName = a.getName();
+
+ Field field = (Field) a.getJavaMember();
+ Column column = field.getAnnotation(Column.class);
+ if (column != null) {
+ attrName = column.name();
+ }
+
+ CollectionTable collectionTable = field.getAnnotation(CollectionTable.class);
+ if (collectionTable != null) {
+ relationTables.put(
+ collectionTable.name(),
+ Pair.of(attrName, collectionTable.joinColumns()[0].name()));
+ }
+
+ JoinTable joinTable = field.getAnnotation(JoinTable.class);
+ if (joinTable != null) {
+ String tableName = joinTable.name();
+ if (StringUtils.isBlank(tableName)) {
+ tableName = entities.getKey(e) + "_"
+ + entities.getKey((EntityType) ((PluralAttribute) a).getElementType());
+ }
+
+ relationTables.put(
+ tableName,
+ Pair.of(joinTable.joinColumns()[0].name(),
+ joinTable.inverseJoinColumns()[0].name()));
+ }
+ }));
+
+ return relationTables;
+ }
+
@Override
public void export(
final String domain,
@@ -409,10 +546,17 @@ public class XMLContentExporter implements ContentExporter {
LOG.debug("Tables to be exported {}", tableNames);
+ EntityManagerFactory emf = EntityManagerFactoryUtils.findEntityManagerFactory(
+ ApplicationContextProvider.getBeanFactory(), domain);
+ Set<EntityType<?>> entityTypes = emf == null ? Collections.emptySet() : emf.getMetamodel().getEntities();
+ BidiMap<String, EntityType<?>> entities = entities(entityTypes);
+
// then sort tables based on foreign keys and dump
for (String tableName : sortByForeignKeys(schema, conn, tableNames)) {
try {
- exportTable(handler, conn, tableName, TABLES_TO_BE_FILTERED.get(tableName.toUpperCase()));
+ exportTable(
+ handler, conn, tableName, TABLES_TO_BE_FILTERED.get(tableName.toUpperCase()),
+ entities, taskEntities(entityTypes), relationTables(entities));
} catch (Exception e) {
LOG.error("Failure exporting table {}", tableName, e);
}
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/XMLContentExporterTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/XMLContentExporterTest.java
index 9d8fef7..97f4ff7 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/XMLContentExporterTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/XMLContentExporterTest.java
@@ -53,13 +53,15 @@ public class XMLContentExporterTest extends AbstractTest {
String exported = baos.toString(Charset.defaultCharset());
assertTrue(StringUtils.isNotBlank(exported));
+ System.out.println("EEEEEEEEEEEEEE\n" + exported);
+
List<String> realms = IOUtils.readLines(
IOUtils.toInputStream(exported, Charset.defaultCharset()), Charset.defaultCharset()).stream().
- filter(row -> StringUtils.startsWithIgnoreCase(row.trim(), "<REALM")).collect(Collectors.toList());
+ filter(row -> row.trim().startsWith("<Realm")).collect(Collectors.toList());
assertEquals(4, realms.size());
- assertTrue(StringUtils.containsIgnoreCase(realms.get(0), "NAME=\"/\""));
- assertTrue(StringUtils.containsIgnoreCase(realms.get(1), "NAME=\"odd\""));
- assertTrue(StringUtils.containsIgnoreCase(realms.get(2), "NAME=\"even\""));
- assertTrue(StringUtils.containsIgnoreCase(realms.get(3), "NAME=\"two\""));
+ assertTrue(realms.get(0).contains("name=\"/\""));
+ assertTrue(realms.get(1).contains("name=\"odd\""));
+ assertTrue(realms.get(2).contains("name=\"even\""));
+ assertTrue(realms.get(3).contains("name=\"two\""));
}
}