You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by ab...@apache.org on 2019/06/27 11:10:14 UTC

[cayenne] branch master updated (4422aa5 -> 7257d0a)

This is an automated email from the ASF dual-hosted git repository.

abulatski pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git.


    from 4422aa5  Merge PR #393
     new a58466a  CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
     new 7fc1031  CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
     new acdfa17  CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
     new 734cae4  CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
     new 7257d0a  Merge PR #392

The 5 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:
 RELEASE-NOTES.txt                                  |   1 +
 .../org/apache/cayenne/crypto/CryptoModule.java    |   2 +-
 .../cayenne/crypto/CryptoServerModuleProvider.java |  11 +-
 .../reader/CryptoRowReaderFactoryDecorator.java    | 212 ++++++++++++++++-----
 .../apache/cayenne/crypto/Runtime_AES128_IT.java   | 208 +++++++++++++++++++-
 .../java/org/apache/cayenne/crypto/db/Table7.java  |   9 +
 .../org/apache/cayenne/crypto/db/auto/_Table1.java |  25 +++
 .../crypto/db/auto/{_Table1.java => _Table7.java}  |  54 ++----
 .../src/test/resources/cayenne-crypto.xml          |   2 +
 cayenne-crypto/src/test/resources/datamap.map.xml  |  20 +-
 .../cayenne/access/jdbc/ColumnDescriptor.java      |   3 -
 .../jdbc/reader/DefaultRowReaderFactory.java       |  28 +--
 12 files changed, 466 insertions(+), 109 deletions(-)
 create mode 100644 cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/Table7.java
 copy cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/{_Table1.java => _Table7.java} (68%)


[cayenne] 01/05: CAY-2584 Crypto: can't use ColumnSelect with encrypted columns

Posted by ab...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

abulatski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit a58466a87ffb48c2abc95a171c93c693f812ea24
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Thu Jun 6 18:09:47 2019 +0300

    CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
---
 .../reader/CryptoRowReaderFactoryDecorator.java    | 155 ++++++++++++++++-----
 .../apache/cayenne/crypto/Runtime_AES128_IT.java   | 100 +++++++++++++
 .../cayenne/access/jdbc/ColumnDescriptor.java      |   4 +
 .../jdbc/reader/DefaultRowReaderFactory.java       |  10 +-
 4 files changed, 228 insertions(+), 41 deletions(-)

diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
index f757da8..524a7fa 100644
--- a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
@@ -20,6 +20,7 @@ package org.apache.cayenne.crypto.reader;
 
 import org.apache.cayenne.access.jdbc.ColumnDescriptor;
 import org.apache.cayenne.access.jdbc.RowDescriptor;
+import org.apache.cayenne.access.jdbc.reader.DefaultRowReaderFactory;
 import org.apache.cayenne.access.jdbc.reader.RowReader;
 import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
 import org.apache.cayenne.access.types.ExtendedType;
@@ -27,68 +28,70 @@ import org.apache.cayenne.access.types.ExtendedTypeMap;
 import org.apache.cayenne.crypto.map.ColumnMapper;
 import org.apache.cayenne.crypto.transformer.MapTransformer;
 import org.apache.cayenne.crypto.transformer.TransformerFactory;
+import org.apache.cayenne.crypto.transformer.bytes.BytesDecryptor;
+import org.apache.cayenne.crypto.transformer.bytes.BytesTransformerFactory;
+import org.apache.cayenne.crypto.transformer.value.ValueDecryptor;
+import org.apache.cayenne.crypto.transformer.value.ValueTransformerFactory;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.query.EntityResultSegment;
 import org.apache.cayenne.query.QueryMetadata;
+import org.apache.cayenne.query.ScalarResultSegment;
 
 import java.sql.ResultSet;
 import java.util.Map;
 
-public class CryptoRowReaderFactoryDecorator implements RowReaderFactory {
+public class CryptoRowReaderFactoryDecorator extends DefaultRowReaderFactory {
 
-    private RowReaderFactory delegate;
     private TransformerFactory transformerFactory;
     private ColumnMapper columnMapper;
+    private BytesTransformerFactory bytesTransformerFactory;
+    private ValueTransformerFactory valueTransformerFactory;
 
     public CryptoRowReaderFactoryDecorator(@Inject RowReaderFactory delegate,
                                            @Inject TransformerFactory transformerFactory,
-                                           @Inject ColumnMapper columnMapper) {
-        this.delegate = delegate;
+                                           @Inject ColumnMapper columnMapper,
+                                           @Inject BytesTransformerFactory bytesTransformerFactory,
+                                           @Inject ValueTransformerFactory valueTransformerFactory) {
         this.transformerFactory = transformerFactory;
         this.columnMapper = columnMapper;
+        this.bytesTransformerFactory = bytesTransformerFactory;
+        this.valueTransformerFactory = valueTransformerFactory;
     }
 
     @Override
-    public RowReader<?> rowReader(final RowDescriptor descriptor, QueryMetadata queryMetadata, DbAdapter adapter,
+    public RowReader<?> rowReader(RowDescriptor descriptor, QueryMetadata queryMetadata, DbAdapter adapter,
                                   Map<ObjAttribute, ColumnDescriptor> attributeOverrides) {
+        RowDescriptor encryptedRowDescriptor = encryptedRowDescriptor(descriptor, adapter.getExtendedTypes());
+        return super.rowReader(encryptedRowDescriptor, queryMetadata, adapter, attributeOverrides);
+    }
 
-        final RowReader<?> delegateReader = delegate.rowReader(encryptedRowDescriptor(descriptor, adapter.getExtendedTypes()),
-                queryMetadata,
-                adapter,
-                attributeOverrides);
-
-        return new RowReader<Object>() {
-
-            private boolean decryptorCompiled;
-            private MapTransformer decryptor;
-
-            private void ensureDecryptorCompiled(Object row) {
-                if (!decryptorCompiled) {
-                    decryptor = transformerFactory.decryptor(descriptor.getColumns(), row);
-                    decryptorCompiled = true;
-                }
-            }
-
-            @Override
-            public Object readRow(ResultSet resultSet) {
-                Object row = delegateReader.readRow(resultSet);
-
-                ensureDecryptorCompiled(row);
-
-                if (decryptor != null) {
-
-                    @SuppressWarnings({"unchecked", "rawtypes"})
-                    Map<String, Object> map = (Map) row;
+    @Override
+    protected RowReader<?> createScalarRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
+                                                 ScalarResultSegment segment) {
+        RowReader<?> scalarRowReader = super
+                .createScalarRowReader(descriptor, queryMetadata, segment);
+        return new DecoratedScalarRowReader(descriptor.getColumns()[segment.getColumnOffset()], scalarRowReader);
+    }
 
-                    decryptor.transform(map);
-                }
+    @Override
+    protected RowReader<?> createEntityRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
+                                                 EntityResultSegment resultMetadata,
+                                                 PostprocessorFactory postProcessorFactory) {
+        RowReader<?> entityRowReader = super
+                .createEntityRowReader(descriptor, queryMetadata, resultMetadata, postProcessorFactory);
+        return new DecoratedFullRowReader(descriptor, entityRowReader);
+    }
 
-                return row;
-            }
-        };
+    @Override
+    protected RowReader<?> createFullRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
+                                               PostprocessorFactory postProcessorFactory) {
+        RowReader<?> fullRowReader = super
+                .createFullRowReader(descriptor, queryMetadata, postProcessorFactory);
+        return new DecoratedFullRowReader(descriptor, fullRowReader);
     }
 
     protected RowDescriptor encryptedRowDescriptor(RowDescriptor descriptor, ExtendedTypeMap typeMap) {
@@ -121,6 +124,82 @@ public class CryptoRowReaderFactoryDecorator implements RowReaderFactory {
             encryptedConverters[i] = t;
         }
 
-        return new RowDescriptor(originalColumns, encryptedConverters);
+        return new DecoratedRowDescriptor(descriptor, originalColumns, encryptedConverters);
+    }
+
+    private static class DecoratedRowDescriptor extends RowDescriptor {
+
+        private final RowDescriptor original;
+
+        DecoratedRowDescriptor(RowDescriptor rowDescriptor, ColumnDescriptor[] columns, ExtendedType[] converters) {
+            this.original = rowDescriptor;
+            this.columns = columns;
+            this.converters = converters;
+        }
+
+        public RowDescriptor unwrap() {
+            return original;
+        }
+    }
+
+    private class DecoratedScalarRowReader implements RowReader<Object> {
+        private final RowReader<?> delegateReader;
+        private final ValueDecryptor valueDecryptor;
+        private final BytesDecryptor bytesDecryptor;
+
+        DecoratedScalarRowReader(ColumnDescriptor descriptor, RowReader<?> delegateReader) {
+            this.delegateReader = delegateReader;
+            if(descriptor.getAttribute() != null && columnMapper.isEncrypted(descriptor.getAttribute())) {
+                this.valueDecryptor = valueTransformerFactory.decryptor(descriptor.getAttribute());
+                this.bytesDecryptor = bytesTransformerFactory.decryptor();
+            } else {
+                this.valueDecryptor = null;
+                this.bytesDecryptor = null;
+            }
+        }
+
+        @Override
+        public Object readRow(ResultSet resultSet) {
+            Object value = delegateReader.readRow(resultSet);
+            if(valueDecryptor == null) {
+                return value;
+            }
+            return valueDecryptor.decrypt(bytesDecryptor, value);
+        }
+    }
+
+    private class DecoratedFullRowReader implements RowReader<Object> {
+
+        private final RowDescriptor descriptor;
+        private final RowReader<?> delegateReader;
+        private boolean decryptorCompiled;
+        private MapTransformer decryptor;
+
+        DecoratedFullRowReader(RowDescriptor descriptor, RowReader<?> delegateReader) {
+            this.descriptor = descriptor;
+            this.delegateReader = delegateReader;
+        }
+
+        private void ensureDecryptorCompiled(Object row) {
+            if (!decryptorCompiled) {
+                decryptor = transformerFactory.decryptor(descriptor.getColumns(), row);
+                decryptorCompiled = true;
+            }
+        }
+
+        @Override
+        public Object readRow(ResultSet resultSet) {
+            Object row = delegateReader.readRow(resultSet);
+
+            ensureDecryptorCompiled(row);
+
+            if (decryptor != null) {
+                @SuppressWarnings("unchecked")
+                Map<String, Object> map = (Map<String, Object>) row;
+                decryptor.transform(map);
+            }
+
+            return row;
+        }
     }
 }
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java
index 8861b7d..338e9d8 100644
--- a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java
@@ -23,6 +23,8 @@ import org.apache.cayenne.crypto.db.Table1;
 import org.apache.cayenne.crypto.db.Table2;
 import org.apache.cayenne.crypto.transformer.value.IntegerConverter;
 import org.apache.cayenne.crypto.unit.CryptoUnitUtils;
+import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.query.SelectQuery;
 import org.junit.Before;
 import org.junit.Test;
@@ -156,4 +158,102 @@ public class Runtime_AES128_IT extends Runtime_AES128_Base {
         assertEquals(61, result.get(0).getCryptoInt());
     }
 
+    @Test
+    public void test_ColumnQueryObject() {
+
+        ObjectContext context = runtime.newContext();
+
+        Table1 t1 = context.newObject(Table1.class);
+        t1.setCryptoInt(1);
+        t1.setCryptoString("test");
+        context.commitChanges();
+
+        List<Table1> result = ObjectSelect
+                .columnQuery(Table1.class, Property.createSelf(Table1.class))
+                .select(context);
+
+        assertEquals(1, result.size());
+        assertEquals(1, result.get(0).getCryptoInt());
+        assertEquals("test", result.get(0).getCryptoString());
+    }
+
+    @Test
+    public void test_ColumnQueryObjectWithPlainScalar() {
+
+        ObjectContext context = runtime.newContext();
+
+        Table1 t1 = context.newObject(Table1.class);
+        t1.setCryptoInt(1);
+        t1.setPlainInt(2);
+        t1.setCryptoString("test");
+        context.commitChanges();
+
+        List<Object[]> result = ObjectSelect
+                .columnQuery(Table1.class, Property.createSelf(Table1.class), Table1.PLAIN_INT)
+                .select(context);
+
+        assertEquals(1, result.size());
+        assertEquals(1, ((Table1)result.get(0)[0]).getCryptoInt());
+        assertEquals("test", ((Table1)result.get(0)[0]).getCryptoString());
+        assertEquals(2, result.get(0)[1]);
+    }
+
+    @Test
+    public void test_ColumnQueryObjectWithEncryptedScalar() {
+
+        ObjectContext context = runtime.newContext();
+
+        Table1 t1 = context.newObject(Table1.class);
+        t1.setCryptoInt(1);
+        t1.setPlainInt(2);
+        t1.setCryptoString("test");
+        context.commitChanges();
+
+        List<Object[]> result = ObjectSelect
+                .columnQuery(Table1.class, Property.createSelf(Table1.class), Table1.CRYPTO_INT)
+                .select(context);
+
+        assertEquals(1, result.size());
+        assertEquals(1, ((Table1)result.get(0)[0]).getCryptoInt());
+        assertEquals("test", ((Table1)result.get(0)[0]).getCryptoString());
+        assertEquals(1, result.get(0)[1]);
+    }
+
+    @Test
+    public void test_ColumnQuerySingleScalar() {
+        ObjectContext context = runtime.newContext();
+
+        Table1 t1 = context.newObject(Table1.class);
+        t1.setCryptoInt(1);
+        t1.setCryptoString("test");
+        context.commitChanges();
+
+        List<String> result = ObjectSelect
+                .columnQuery(Table1.class, Table1.CRYPTO_STRING)
+                .select(context);
+
+        assertEquals(1, result.size());
+        assertEquals("test", result.get(0));
+    }
+
+    @Test
+    public void test_ColumnQueryMultipleScalars() {
+        ObjectContext context = runtime.newContext();
+
+        Table1 t1 = context.newObject(Table1.class);
+        t1.setCryptoInt(1);
+        t1.setCryptoString("test");
+        t1.setPlainInt(2);
+        context.commitChanges();
+
+        List<Object[]> result = ObjectSelect
+                .columnQuery(Table1.class, Table1.CRYPTO_STRING, Table1.CRYPTO_INT, Table1.PLAIN_INT)
+                .select(context);
+
+        assertEquals(1, result.size());
+        assertEquals("test", result.get(0)[0]);
+        assertEquals(1, result.get(0)[1]);
+        assertEquals(2, result.get(0)[2]);
+    }
+
 }
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ColumnDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ColumnDescriptor.java
index abe25d4..a2eeed9 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ColumnDescriptor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ColumnDescriptor.java
@@ -149,6 +149,10 @@ public class ColumnDescriptor {
         return name;
     }
 
+    public void setAttribute(DbAttribute attribute) {
+        this.attribute = attribute;
+    }
+
     /**
      * Returns a DbAttribute for this column. Since columns descriptors can be
      * initialized in a context where a DbAttribite is unknown, this method may
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java
index 9ae3139..8229f17 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java
@@ -70,7 +70,7 @@ public class DefaultRowReaderFactory implements RowReaderFactory {
 				return createEntityRowReader(descriptor, queryMetadata, (EntityResultSegment) segment,
 						postProcessorFactory);
 			} else {
-				return new ScalarRowReader<>(descriptor, (ScalarResultSegment) segment);
+				return createScalarRowReader(descriptor, queryMetadata, (ScalarResultSegment) segment);
 			}
 		} else {
 			CompoundRowReader reader = new CompoundRowReader(resultWidth);
@@ -84,7 +84,7 @@ public class DefaultRowReaderFactory implements RowReaderFactory {
 							createEntityRowReader(descriptor, queryMetadata, (EntityResultSegment) segment,
 									postProcessorFactory));
 				} else {
-					reader.addRowReader(i, new ScalarRowReader<>(descriptor, (ScalarResultSegment) segment));
+					reader.addRowReader(i, createScalarRowReader(descriptor, queryMetadata, (ScalarResultSegment) segment));
 				}
 			}
 
@@ -92,7 +92,11 @@ public class DefaultRowReaderFactory implements RowReaderFactory {
 		}
 	}
 
-	private RowReader<?> createEntityRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
+	protected RowReader<?> createScalarRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata, ScalarResultSegment segment) {
+		return new ScalarRowReader<Object>(descriptor, segment);
+	}
+
+	protected RowReader<?> createEntityRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
 			EntityResultSegment resultMetadata, PostprocessorFactory postProcessorFactory) {
 
 		if (queryMetadata.getPageSize() > 0) {


[cayenne] 02/05: CAY-2584 Crypto: can't use ColumnSelect with encrypted columns

Posted by ab...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

abulatski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 7fc1031280998b3c7ebdf1e7fa49a34ad888e600
Author: Arseni Bulatski <an...@gmail.com>
AuthorDate: Mon Jun 10 12:39:57 2019 +0300

    CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
---
 .../java/org/apache/cayenne/crypto/CryptoModule.java   |  2 +-
 .../cayenne/crypto/CryptoServerModuleProvider.java     | 11 ++++++-----
 .../crypto/reader/CryptoRowReaderFactoryDecorator.java | 10 ++++------
 .../access/jdbc/reader/DefaultRowReaderFactory.java    | 18 +++++++++---------
 4 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModule.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModule.java
index 597f34d..3c08c8e 100644
--- a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModule.java
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModule.java
@@ -139,7 +139,7 @@ public class CryptoModule implements Module {
         binder.bind(ColumnMapper.class).toInstance(new PatternColumnMapper(DEFAULT_COLUMN_MAPPER_PATTERN));
 
         binder.decorate(BatchTranslatorFactory.class).before(CryptoBatchTranslatorFactoryDecorator.class);
-        binder.decorate(RowReaderFactory.class).before(CryptoRowReaderFactoryDecorator.class);
+        binder.bind(RowReaderFactory.class).to(CryptoRowReaderFactoryDecorator.class);
 
         // decorate Crypto's own services to allow Cayenne to operate over plaintext entities even if crypto keys are
         // not available.
diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoServerModuleProvider.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoServerModuleProvider.java
index 8e7fa4d..9c62bb5 100644
--- a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoServerModuleProvider.java
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoServerModuleProvider.java
@@ -18,12 +18,13 @@
  */
 package org.apache.cayenne.crypto;
 
-import org.apache.cayenne.configuration.server.CayenneServerModuleProvider;
-import org.apache.cayenne.di.Module;
-
 import java.util.Collection;
 import java.util.Collections;
 
+import org.apache.cayenne.configuration.server.CayenneServerModuleProvider;
+import org.apache.cayenne.configuration.server.ServerModule;
+import org.apache.cayenne.di.Module;
+
 /**
  * @since 4.0
  */
@@ -41,7 +42,7 @@ public class CryptoServerModuleProvider implements CayenneServerModuleProvider {
 
     @Override
     public Collection<Class<? extends Module>> overrides() {
-        // we don't override anything, we only decorate ServerModule services...
-        return Collections.emptyList();
+        Collection modules = Collections.singletonList(ServerModule.class);
+        return modules;
     }
 }
diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
index 524a7fa..688d787 100644
--- a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
@@ -18,11 +18,13 @@
  ****************************************************************/
 package org.apache.cayenne.crypto.reader;
 
+import java.sql.ResultSet;
+import java.util.Map;
+
 import org.apache.cayenne.access.jdbc.ColumnDescriptor;
 import org.apache.cayenne.access.jdbc.RowDescriptor;
 import org.apache.cayenne.access.jdbc.reader.DefaultRowReaderFactory;
 import org.apache.cayenne.access.jdbc.reader.RowReader;
-import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
 import org.apache.cayenne.access.types.ExtendedType;
 import org.apache.cayenne.access.types.ExtendedTypeMap;
 import org.apache.cayenne.crypto.map.ColumnMapper;
@@ -41,9 +43,6 @@ import org.apache.cayenne.query.EntityResultSegment;
 import org.apache.cayenne.query.QueryMetadata;
 import org.apache.cayenne.query.ScalarResultSegment;
 
-import java.sql.ResultSet;
-import java.util.Map;
-
 public class CryptoRowReaderFactoryDecorator extends DefaultRowReaderFactory {
 
     private TransformerFactory transformerFactory;
@@ -51,8 +50,7 @@ public class CryptoRowReaderFactoryDecorator extends DefaultRowReaderFactory {
     private BytesTransformerFactory bytesTransformerFactory;
     private ValueTransformerFactory valueTransformerFactory;
 
-    public CryptoRowReaderFactoryDecorator(@Inject RowReaderFactory delegate,
-                                           @Inject TransformerFactory transformerFactory,
+    public CryptoRowReaderFactoryDecorator(@Inject TransformerFactory transformerFactory,
                                            @Inject ColumnMapper columnMapper,
                                            @Inject BytesTransformerFactory bytesTransformerFactory,
                                            @Inject ValueTransformerFactory valueTransformerFactory) {
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java
index 8229f17..db41752 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java
@@ -18,6 +18,13 @@
  ****************************************************************/
 package org.apache.cayenne.access.jdbc.reader;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.jdbc.ColumnDescriptor;
 import org.apache.cayenne.access.jdbc.RowDescriptor;
@@ -33,13 +40,6 @@ import org.apache.cayenne.query.QueryMetadata;
 import org.apache.cayenne.query.ScalarResultSegment;
 import org.apache.cayenne.reflect.ClassDescriptor;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
 /**
  * @since 4.0
  */
@@ -108,7 +108,7 @@ public class DefaultRowReaderFactory implements RowReaderFactory {
 		}
 	}
 
-	private RowReader<?> createFullRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
+	protected RowReader<?> createFullRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
 			PostprocessorFactory postProcessorFactory) {
 
 		if (queryMetadata.getPageSize() > 0) {
@@ -120,7 +120,7 @@ public class DefaultRowReaderFactory implements RowReaderFactory {
 		}
 	}
 
-	private class PostprocessorFactory {
+	protected class PostprocessorFactory {
 
 		private QueryMetadata queryMetadata;
 		private ExtendedTypeMap extendedTypes;


[cayenne] 05/05: Merge PR #392

Posted by ab...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

abulatski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 7257d0af94c69d669351805f52d287f20dae23dd
Merge: 4422aa5 734cae4
Author: Arseni Bulatski <an...@gmail.com>
AuthorDate: Thu Jun 27 14:09:12 2019 +0300

    Merge PR #392

 RELEASE-NOTES.txt                                  |   1 +
 .../org/apache/cayenne/crypto/CryptoModule.java    |   2 +-
 .../cayenne/crypto/CryptoServerModuleProvider.java |  11 +-
 .../reader/CryptoRowReaderFactoryDecorator.java    | 212 ++++++++++++++++-----
 .../apache/cayenne/crypto/Runtime_AES128_IT.java   | 208 +++++++++++++++++++-
 .../java/org/apache/cayenne/crypto/db/Table7.java  |   9 +
 .../org/apache/cayenne/crypto/db/auto/_Table1.java |  25 +++
 .../crypto/db/auto/{_Table1.java => _Table7.java}  |  54 ++----
 .../src/test/resources/cayenne-crypto.xml          |   2 +
 cayenne-crypto/src/test/resources/datamap.map.xml  |  20 +-
 .../cayenne/access/jdbc/ColumnDescriptor.java      |   3 -
 .../jdbc/reader/DefaultRowReaderFactory.java       |  28 +--
 12 files changed, 466 insertions(+), 109 deletions(-)

diff --cc RELEASE-NOTES.txt
index 39f91cd,337e6e0..8f0ecc7
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@@ -60,7 -60,7 +60,8 @@@ CAY-2577 Between property with extende
  CAY-2578 Wrong bindings in select of related entity by compound FK
  CAY-2580 Cgen: Can't use custom templates for client mode
  CAY-2582 Double insert of manyToMany relationship mapped to Set
+ CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
 +CAY-2588 IdRowReader: ArrayIndexOutOfBoundsException
  
  ----------------------------------
  Release: 4.1.B1


[cayenne] 03/05: CAY-2584 Crypto: can't use ColumnSelect with encrypted columns

Posted by ab...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

abulatski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit acdfa178dc75e52be39540b2269ba41e2ec03f75
Author: Arseni Bulatski <an...@gmail.com>
AuthorDate: Fri Jun 21 11:28:14 2019 +0300

    CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
---
 RELEASE-NOTES.txt                                  |   1 +
 .../crypto/transformer/DefaultMapTransformer.java  |   6 ++
 .../apache/cayenne/crypto/Runtime_AES128_IT.java   | 105 +++++++++++++++++++--
 .../java/org/apache/cayenne/crypto/db/Table7.java  |   9 ++
 .../org/apache/cayenne/crypto/db/auto/_Table1.java |  25 +++++
 .../crypto/db/auto/{_Table1.java => _Table7.java}  |  54 ++++-------
 .../src/test/resources/cayenne-crypto.xml          |   2 +
 cayenne-crypto/src/test/resources/datamap.map.xml  |  20 +++-
 .../cayenne/access/jdbc/ColumnDescriptor.java      |   7 --
 9 files changed, 177 insertions(+), 52 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 1fa3317..337e6e0 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -60,6 +60,7 @@ CAY-2577 Between property with extended type failure
 CAY-2578 Wrong bindings in select of related entity by compound FK
 CAY-2580 Cgen: Can't use custom templates for client mode
 CAY-2582 Double insert of manyToMany relationship mapped to Set
+CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
 
 ----------------------------------
 Release: 4.1.B1
diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultMapTransformer.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultMapTransformer.java
index 5c778b0..622d8d7 100644
--- a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultMapTransformer.java
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultMapTransformer.java
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.crypto.transformer;
 
+import java.util.Arrays;
 import java.util.Map;
 
 import org.apache.cayenne.crypto.transformer.bytes.BytesDecryptor;
@@ -41,6 +42,7 @@ public class DefaultMapTransformer implements MapTransformer {
     @Override
     public void transform(Map<String, Object> map) {
 
+        mapKeys = mergeSameKeys(mapKeys);
         int len = mapKeys.length;
 
         for (int i = 0; i < len; i++) {
@@ -52,4 +54,8 @@ public class DefaultMapTransformer implements MapTransformer {
             }
         }
     }
+
+    private String[] mergeSameKeys(String[] keys) {
+        return Arrays.stream(keys).distinct().toArray(String[]::new);
+    }
 }
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java
index 338e9d8..6dddecd 100644
--- a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java
@@ -18,25 +18,28 @@
  ****************************************************************/
 package org.apache.cayenne.crypto;
 
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.crypto.db.Table1;
 import org.apache.cayenne.crypto.db.Table2;
+import org.apache.cayenne.crypto.db.Table7;
 import org.apache.cayenne.crypto.transformer.value.IntegerConverter;
 import org.apache.cayenne.crypto.unit.CryptoUnitUtils;
 import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.query.SelectQuery;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.sql.SQLException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 public class Runtime_AES128_IT extends Runtime_AES128_Base {
 
@@ -207,10 +210,11 @@ public class Runtime_AES128_IT extends Runtime_AES128_Base {
         t1.setCryptoInt(1);
         t1.setPlainInt(2);
         t1.setCryptoString("test");
+        t1.setPlainString("Test");
         context.commitChanges();
 
         List<Object[]> result = ObjectSelect
-                .columnQuery(Table1.class, Property.createSelf(Table1.class), Table1.CRYPTO_INT)
+                .columnQuery(Table1.class, PropertyFactory.createSelf(Table1.class), Table1.CRYPTO_INT)
                 .select(context);
 
         assertEquals(1, result.size());
@@ -220,6 +224,95 @@ public class Runtime_AES128_IT extends Runtime_AES128_Base {
     }
 
     @Test
+    public void testColumnQueryWithRelationshipWithTheSameNames() {
+        ObjectContext context = runtime.newContext();
+
+        Table1 t1 = context.newObject(Table1.class);
+        t1.setCryptoInt(1);
+        t1.setPlainInt(3);
+        t1.setCryptoString("test");
+        t1.setPlainString("Test");
+
+        Table7 t7 = context.newObject(Table7.class);
+        t7.setCryptoInt(2);
+        t7.setCryptoString("string");
+
+        t1.addToTable7s(t7);
+
+        context.commitChanges();
+
+        List<Object[]> result = ObjectSelect
+                .columnQuery(Table1.class,
+                        PropertyFactory.createSelf(Table1.class),
+                        Table1.CRYPTO_INT,
+                        Table1.TABLE7S.dot(Table7.CRYPTO_INT),
+                        Table1.TABLE7S.dot(Table7.CRYPTO_STRING))
+                .select(context);
+        assertEquals(1, result.size());
+        assertEquals(1, ((Table1)result.get(0)[0]).getCryptoInt());
+        assertEquals("test", ((Table1)result.get(0)[0]).getCryptoString());
+        assertEquals(1, result.get(0)[1]);
+        assertEquals(2, result.get(0)[2]);
+        assertEquals("string", result.get(0)[3]);
+    }
+
+    @Test
+    public void testSelectWith2Objects() {
+        ObjectContext context = runtime.newContext();
+
+        Table1 t1 = context.newObject(Table1.class);
+        t1.setCryptoInt(1);
+        t1.setPlainInt(3);
+        t1.setCryptoString("test");
+        t1.setPlainString("Test");
+
+        Table7 t7 = context.newObject(Table7.class);
+        t7.setCryptoInt(2);
+        t7.setCryptoString("string");
+
+        t1.addToTable7s(t7);
+
+        context.commitChanges();
+
+        List<Object[]> result = ObjectSelect
+                .columnQuery(Table1.class,
+                        PropertyFactory.createSelf(Table1.class),
+                        Table1.TABLE7S.flat())
+                .select(context);
+        assertEquals(1, result.size());
+        assertEquals("test", ((Table1)result.get(0)[0]).getCryptoString());
+        assertTrue(result.get(0)[1] instanceof Table7);
+        assertEquals(2, ((Table7)result.get(0)[1]).getCryptoInt());
+    }
+
+    @Test
+    public void testObjectSelectWithPrefetch() {
+        ObjectContext context = runtime.newContext();
+
+        Table1 t1 = context.newObject(Table1.class);
+        t1.setCryptoInt(1);
+        t1.setPlainInt(3);
+        t1.setCryptoString("test");
+        t1.setPlainString("Test");
+
+        Table7 t7 = context.newObject(Table7.class);
+        t7.setCryptoInt(2);
+        t7.setCryptoString("string");
+
+        t1.addToTable7s(t7);
+
+        context.commitChanges();
+
+        List<Table1> table1s = ObjectSelect.query(Table1.class)
+                .prefetch(Table1.TABLE7S.disjoint())
+                .select(context);
+
+        assertEquals(1, table1s.size());
+        assertEquals("test", table1s.get(0).getCryptoString());
+        assertEquals("string", table1s.get(0).getTable7s().get(0).getCryptoString());
+    }
+
+    @Test
     public void test_ColumnQuerySingleScalar() {
         ObjectContext context = runtime.newContext();
 
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/Table7.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/Table7.java
new file mode 100644
index 0000000..2d65080
--- /dev/null
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/Table7.java
@@ -0,0 +1,9 @@
+package org.apache.cayenne.crypto.db;
+
+import org.apache.cayenne.crypto.db.auto._Table7;
+
+public class Table7 extends _Table7 {
+
+    private static final long serialVersionUID = 1L; 
+
+}
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
index 0d32a17..71855de 100644
--- a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
@@ -3,8 +3,11 @@ package org.apache.cayenne.crypto.db.auto;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.util.List;
 
 import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.crypto.db.Table7;
+import org.apache.cayenne.exp.property.ListProperty;
 import org.apache.cayenne.exp.property.NumericProperty;
 import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.exp.property.StringProperty;
@@ -25,12 +28,14 @@ public abstract class _Table1 extends BaseDataObject {
     public static final StringProperty<String> CRYPTO_STRING = PropertyFactory.createString("cryptoString", String.class);
     public static final NumericProperty<Integer> PLAIN_INT = PropertyFactory.createNumeric("plainInt", Integer.class);
     public static final StringProperty<String> PLAIN_STRING = PropertyFactory.createString("plainString", String.class);
+    public static final ListProperty<Table7> TABLE7S = PropertyFactory.createList("table7s", Table7.class);
 
     protected Integer cryptoInt;
     protected String cryptoString;
     protected Integer plainInt;
     protected String plainString;
 
+    protected Object table7s;
 
     public void setCryptoInt(int cryptoInt) {
         beforePropertyWrite("cryptoInt", this.cryptoInt, cryptoInt);
@@ -78,6 +83,19 @@ public abstract class _Table1 extends BaseDataObject {
         return this.plainString;
     }
 
+    public void addToTable7s(Table7 obj) {
+        addToManyTarget("table7s", obj, true);
+    }
+
+    public void removeFromTable7s(Table7 obj) {
+        removeToManyTarget("table7s", obj, true);
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<Table7> getTable7s() {
+        return (List<Table7>)readProperty("table7s");
+    }
+
     @Override
     public Object readPropertyDirectly(String propName) {
         if(propName == null) {
@@ -93,6 +111,8 @@ public abstract class _Table1 extends BaseDataObject {
                 return this.plainInt;
             case "plainString":
                 return this.plainString;
+            case "table7s":
+                return this.table7s;
             default:
                 return super.readPropertyDirectly(propName);
         }
@@ -117,6 +137,9 @@ public abstract class _Table1 extends BaseDataObject {
             case "plainString":
                 this.plainString = (String)val;
                 break;
+            case "table7s":
+                this.table7s = val;
+                break;
             default:
                 super.writePropertyDirectly(propName, val);
         }
@@ -137,6 +160,7 @@ public abstract class _Table1 extends BaseDataObject {
         out.writeObject(this.cryptoString);
         out.writeObject(this.plainInt);
         out.writeObject(this.plainString);
+        out.writeObject(this.table7s);
     }
 
     @Override
@@ -146,6 +170,7 @@ public abstract class _Table1 extends BaseDataObject {
         this.cryptoString = (String)in.readObject();
         this.plainInt = (Integer)in.readObject();
         this.plainString = (String)in.readObject();
+        this.table7s = in.readObject();
     }
 
 }
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table7.java
similarity index 68%
copy from cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
copy to cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table7.java
index 0d32a17..3964c74 100644
--- a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table7.java
@@ -5,17 +5,19 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 
 import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.crypto.db.Table1;
+import org.apache.cayenne.exp.property.EntityProperty;
 import org.apache.cayenne.exp.property.NumericProperty;
 import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.exp.property.StringProperty;
 
 /**
- * Class _Table1 was generated by Cayenne.
+ * Class _Table7 was generated by Cayenne.
  * It is probably a good idea to avoid changing this class manually,
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Table1 extends BaseDataObject {
+public abstract class _Table7 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
@@ -23,14 +25,12 @@ public abstract class _Table1 extends BaseDataObject {
 
     public static final NumericProperty<Integer> CRYPTO_INT = PropertyFactory.createNumeric("cryptoInt", Integer.class);
     public static final StringProperty<String> CRYPTO_STRING = PropertyFactory.createString("cryptoString", String.class);
-    public static final NumericProperty<Integer> PLAIN_INT = PropertyFactory.createNumeric("plainInt", Integer.class);
-    public static final StringProperty<String> PLAIN_STRING = PropertyFactory.createString("plainString", String.class);
+    public static final EntityProperty<Table1> TO_TABLE1 = PropertyFactory.createEntity("toTable1", Table1.class);
 
     protected Integer cryptoInt;
     protected String cryptoString;
-    protected Integer plainInt;
-    protected String plainString;
 
+    protected Object toTable1;
 
     public void setCryptoInt(int cryptoInt) {
         beforePropertyWrite("cryptoInt", this.cryptoInt, cryptoInt);
@@ -55,27 +55,12 @@ public abstract class _Table1 extends BaseDataObject {
         return this.cryptoString;
     }
 
-    public void setPlainInt(int plainInt) {
-        beforePropertyWrite("plainInt", this.plainInt, plainInt);
-        this.plainInt = plainInt;
+    public void setToTable1(Table1 toTable1) {
+        setToOneTarget("toTable1", toTable1, true);
     }
 
-    public int getPlainInt() {
-        beforePropertyRead("plainInt");
-        if(this.plainInt == null) {
-            return 0;
-        }
-        return this.plainInt;
-    }
-
-    public void setPlainString(String plainString) {
-        beforePropertyWrite("plainString", this.plainString, plainString);
-        this.plainString = plainString;
-    }
-
-    public String getPlainString() {
-        beforePropertyRead("plainString");
-        return this.plainString;
+    public Table1 getToTable1() {
+        return (Table1)readProperty("toTable1");
     }
 
     @Override
@@ -89,10 +74,8 @@ public abstract class _Table1 extends BaseDataObject {
                 return this.cryptoInt;
             case "cryptoString":
                 return this.cryptoString;
-            case "plainInt":
-                return this.plainInt;
-            case "plainString":
-                return this.plainString;
+            case "toTable1":
+                return this.toTable1;
             default:
                 return super.readPropertyDirectly(propName);
         }
@@ -111,11 +94,8 @@ public abstract class _Table1 extends BaseDataObject {
             case "cryptoString":
                 this.cryptoString = (String)val;
                 break;
-            case "plainInt":
-                this.plainInt = (Integer)val;
-                break;
-            case "plainString":
-                this.plainString = (String)val;
+            case "toTable1":
+                this.toTable1 = val;
                 break;
             default:
                 super.writePropertyDirectly(propName, val);
@@ -135,8 +115,7 @@ public abstract class _Table1 extends BaseDataObject {
         super.writeState(out);
         out.writeObject(this.cryptoInt);
         out.writeObject(this.cryptoString);
-        out.writeObject(this.plainInt);
-        out.writeObject(this.plainString);
+        out.writeObject(this.toTable1);
     }
 
     @Override
@@ -144,8 +123,7 @@ public abstract class _Table1 extends BaseDataObject {
         super.readState(in);
         this.cryptoInt = (Integer)in.readObject();
         this.cryptoString = (String)in.readObject();
-        this.plainInt = (Integer)in.readObject();
-        this.plainString = (String)in.readObject();
+        this.toTable1 = in.readObject();
     }
 
 }
diff --git a/cayenne-crypto/src/test/resources/cayenne-crypto.xml b/cayenne-crypto/src/test/resources/cayenne-crypto.xml
index 1680c10..dea206b 100644
--- a/cayenne-crypto/src/test/resources/cayenne-crypto.xml
+++ b/cayenne-crypto/src/test/resources/cayenne-crypto.xml
@@ -1,5 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <domain xmlns="http://cayenne.apache.org/schema/10/domain"
+	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	 xsi:schemaLocation="http://cayenne.apache.org/schema/10/domain https://cayenne.apache.org/schema/10/domain.xsd"
 	 project-version="10">
 	<map name="datamap"/>
 	<node name="datanode"
diff --git a/cayenne-crypto/src/test/resources/datamap.map.xml b/cayenne-crypto/src/test/resources/datamap.map.xml
index fd572a8..6c40f2c 100644
--- a/cayenne-crypto/src/test/resources/datamap.map.xml
+++ b/cayenne-crypto/src/test/resources/datamap.map.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <data-map xmlns="http://cayenne.apache.org/schema/10/modelMap"
 	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	 xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap http://cayenne.apache.org/schema/10/modelMap.xsd"
+	 xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap https://cayenne.apache.org/schema/10/modelMap.xsd"
 	 project-version="10">
 	<property name="defaultPackage" value="org.apache.cayenne.crypto.db"/>
 	<db-entity name="TABLE1">
@@ -32,6 +32,12 @@
 		<db-attribute name="CRYPTO_INT4" type="BLOB"/>
 		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
 	</db-entity>
+	<db-entity name="TABLE7">
+		<db-attribute name="CRYPTO_INT" type="BLOB"/>
+		<db-attribute name="CRYPTO_STRING" type="CLOB"/>
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="TABLE1_ID" type="INTEGER"/>
+	</db-entity>
 	<obj-entity name="Table1" className="org.apache.cayenne.crypto.db.Table1" dbEntityName="TABLE1">
 		<obj-attribute name="cryptoInt" type="int" db-attribute-path="CRYPTO_INT"/>
 		<obj-attribute name="cryptoString" type="java.lang.String" db-attribute-path="CRYPTO_STRING"/>
@@ -58,4 +64,16 @@
 		<obj-attribute name="cryptoInt1" type="long" db-attribute-path="CRYPTO_INT1"/>
 		<obj-attribute name="cryptoInt4" type="int" db-attribute-path="CRYPTO_INT4"/>
 	</obj-entity>
+	<obj-entity name="Table7" className="org.apache.cayenne.crypto.db.Table7" dbEntityName="TABLE7">
+		<obj-attribute name="cryptoInt" type="int" db-attribute-path="CRYPTO_INT"/>
+		<obj-attribute name="cryptoString" type="java.lang.String" db-attribute-path="CRYPTO_STRING"/>
+	</obj-entity>
+	<db-relationship name="table7s" source="TABLE1" target="TABLE7" toMany="true">
+		<db-attribute-pair source="ID" target="TABLE1_ID"/>
+	</db-relationship>
+	<db-relationship name="toTable1" source="TABLE7" target="TABLE1">
+		<db-attribute-pair source="TABLE1_ID" target="ID"/>
+	</db-relationship>
+	<obj-relationship name="table7s" source="Table1" target="Table7" deleteRule="Deny" db-relationship-path="table7s"/>
+	<obj-relationship name="toTable1" source="Table7" target="Table1" deleteRule="Nullify" db-relationship-path="toTable1"/>
 </data-map>
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ColumnDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ColumnDescriptor.java
index a2eeed9..ea30eb9 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ColumnDescriptor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ColumnDescriptor.java
@@ -149,10 +149,6 @@ public class ColumnDescriptor {
         return name;
     }
 
-    public void setAttribute(DbAttribute attribute) {
-        this.attribute = attribute;
-    }
-
     /**
      * Returns a DbAttribute for this column. Since columns descriptors can be
      * initialized in a context where a DbAttribite is unknown, this method may
@@ -164,9 +160,6 @@ public class ColumnDescriptor {
         return attribute;
     }
 
-    /**
-     * @since 4.2
-     */
     public void setAttribute(DbAttribute attribute) {
         this.attribute = attribute;
     }


[cayenne] 04/05: CAY-2584 Crypto: can't use ColumnSelect with encrypted columns

Posted by ab...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

abulatski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 734cae4d7cceb20b7c6182b6a2bd55d427636ec0
Author: Arseni Bulatski <an...@gmail.com>
AuthorDate: Thu Jun 27 13:47:28 2019 +0300

    CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
---
 .../reader/CryptoRowReaderFactoryDecorator.java    | 73 ++++++++++++++++++----
 .../crypto/transformer/DefaultMapTransformer.java  |  6 --
 .../apache/cayenne/crypto/Runtime_AES128_IT.java   | 23 ++++---
 3 files changed, 74 insertions(+), 28 deletions(-)

diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
index 688d787..bb818a8 100644
--- a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
@@ -81,7 +81,7 @@ public class CryptoRowReaderFactoryDecorator extends DefaultRowReaderFactory {
                                                  PostprocessorFactory postProcessorFactory) {
         RowReader<?> entityRowReader = super
                 .createEntityRowReader(descriptor, queryMetadata, resultMetadata, postProcessorFactory);
-        return new DecoratedFullRowReader(descriptor, entityRowReader);
+        return new DecoratedEntityRowReader(descriptor, entityRowReader, resultMetadata);
     }
 
     @Override
@@ -166,24 +166,23 @@ public class CryptoRowReaderFactoryDecorator extends DefaultRowReaderFactory {
         }
     }
 
-    private class DecoratedFullRowReader implements RowReader<Object> {
+    private abstract class DecoratedEntityFullRowReader implements RowReader<Object> {
 
-        private final RowDescriptor descriptor;
-        private final RowReader<?> delegateReader;
-        private boolean decryptorCompiled;
-        private MapTransformer decryptor;
+        final RowDescriptor descriptor;
+        final RowReader<?> delegateReader;
+        final EntityResultSegment resultMetadata;
+        boolean decryptorCompiled;
+        MapTransformer decryptor;
 
-        DecoratedFullRowReader(RowDescriptor descriptor, RowReader<?> delegateReader) {
+        DecoratedEntityFullRowReader(RowDescriptor descriptor,
+                                 RowReader<?> delegateReader,
+                                 EntityResultSegment resultMetadata) {
             this.descriptor = descriptor;
             this.delegateReader = delegateReader;
+            this.resultMetadata = resultMetadata;
         }
 
-        private void ensureDecryptorCompiled(Object row) {
-            if (!decryptorCompiled) {
-                decryptor = transformerFactory.decryptor(descriptor.getColumns(), row);
-                decryptorCompiled = true;
-            }
-        }
+        abstract void ensureDecryptorCompiled(Object row);
 
         @Override
         public Object readRow(ResultSet resultSet) {
@@ -200,4 +199,52 @@ public class CryptoRowReaderFactoryDecorator extends DefaultRowReaderFactory {
             return row;
         }
     }
+
+    private class DecoratedEntityRowReader extends DecoratedEntityFullRowReader {
+
+        DecoratedEntityRowReader(RowDescriptor descriptor,
+                                 RowReader<?> delegateReader,
+                                 EntityResultSegment resultMetadata) {
+            super(descriptor, delegateReader, resultMetadata);
+        }
+
+        void ensureDecryptorCompiled(Object row) {
+            if (!decryptorCompiled) {
+                int offset = resultMetadata.getColumnOffset();
+                int fieldsSize = resultMetadata.getFields().size();
+                ColumnDescriptor[] columnDescriptors =
+                        new ColumnDescriptor[fieldsSize];
+                for(int i = offset, j = 0; i < offset + fieldsSize; i++) {
+                    columnDescriptors[j++] = descriptor.getColumns()[i];
+                }
+                decryptor = transformerFactory.decryptor(columnDescriptors, row);
+                decryptorCompiled = true;
+            }
+        }
+
+        @Override
+        public Object readRow(ResultSet resultSet) {
+            return super.readRow(resultSet);
+        }
+    }
+
+    private class DecoratedFullRowReader extends DecoratedEntityFullRowReader {
+
+        DecoratedFullRowReader(RowDescriptor descriptor,
+                               RowReader<?> delegateReader) {
+            super(descriptor, delegateReader, null);
+        }
+
+        void ensureDecryptorCompiled(Object row) {
+            if (!decryptorCompiled) {
+                decryptor = transformerFactory.decryptor(descriptor.getColumns(), row);
+                decryptorCompiled = true;
+            }
+        }
+
+        @Override
+        public Object readRow(ResultSet resultSet) {
+            return super.readRow(resultSet);
+        }
+    }
 }
diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultMapTransformer.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultMapTransformer.java
index 622d8d7..5c778b0 100644
--- a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultMapTransformer.java
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultMapTransformer.java
@@ -18,7 +18,6 @@
  ****************************************************************/
 package org.apache.cayenne.crypto.transformer;
 
-import java.util.Arrays;
 import java.util.Map;
 
 import org.apache.cayenne.crypto.transformer.bytes.BytesDecryptor;
@@ -42,7 +41,6 @@ public class DefaultMapTransformer implements MapTransformer {
     @Override
     public void transform(Map<String, Object> map) {
 
-        mapKeys = mergeSameKeys(mapKeys);
         int len = mapKeys.length;
 
         for (int i = 0; i < len; i++) {
@@ -54,8 +52,4 @@ public class DefaultMapTransformer implements MapTransformer {
             }
         }
     }
-
-    private String[] mergeSameKeys(String[] keys) {
-        return Arrays.stream(keys).distinct().toArray(String[]::new);
-    }
 }
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java
index 6dddecd..88b3072 100644
--- a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java
@@ -29,7 +29,6 @@ import org.apache.cayenne.crypto.db.Table2;
 import org.apache.cayenne.crypto.db.Table7;
 import org.apache.cayenne.crypto.transformer.value.IntegerConverter;
 import org.apache.cayenne.crypto.unit.CryptoUnitUtils;
-import org.apache.cayenne.exp.Property;
 import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.query.SelectQuery;
@@ -172,7 +171,7 @@ public class Runtime_AES128_IT extends Runtime_AES128_Base {
         context.commitChanges();
 
         List<Table1> result = ObjectSelect
-                .columnQuery(Table1.class, Property.createSelf(Table1.class))
+                .columnQuery(Table1.class, PropertyFactory.createSelf(Table1.class))
                 .select(context);
 
         assertEquals(1, result.size());
@@ -192,7 +191,9 @@ public class Runtime_AES128_IT extends Runtime_AES128_Base {
         context.commitChanges();
 
         List<Object[]> result = ObjectSelect
-                .columnQuery(Table1.class, Property.createSelf(Table1.class), Table1.PLAIN_INT)
+                .columnQuery(Table1.class,
+                        PropertyFactory.createSelf(Table1.class),
+                        Table1.PLAIN_INT)
                 .select(context);
 
         assertEquals(1, result.size());
@@ -214,7 +215,9 @@ public class Runtime_AES128_IT extends Runtime_AES128_Base {
         context.commitChanges();
 
         List<Object[]> result = ObjectSelect
-                .columnQuery(Table1.class, PropertyFactory.createSelf(Table1.class), Table1.CRYPTO_INT)
+                .columnQuery(Table1.class,
+                        PropertyFactory.createSelf(Table1.class),
+                        Table1.CRYPTO_INT)
                 .select(context);
 
         assertEquals(1, result.size());
@@ -243,17 +246,19 @@ public class Runtime_AES128_IT extends Runtime_AES128_Base {
 
         List<Object[]> result = ObjectSelect
                 .columnQuery(Table1.class,
+                        Table1.CRYPTO_INT,
                         PropertyFactory.createSelf(Table1.class),
                         Table1.CRYPTO_INT,
                         Table1.TABLE7S.dot(Table7.CRYPTO_INT),
                         Table1.TABLE7S.dot(Table7.CRYPTO_STRING))
                 .select(context);
         assertEquals(1, result.size());
-        assertEquals(1, ((Table1)result.get(0)[0]).getCryptoInt());
-        assertEquals("test", ((Table1)result.get(0)[0]).getCryptoString());
-        assertEquals(1, result.get(0)[1]);
-        assertEquals(2, result.get(0)[2]);
-        assertEquals("string", result.get(0)[3]);
+        assertEquals(1, result.get(0)[0]);
+        assertEquals(1, ((Table1)result.get(0)[1]).getCryptoInt());
+        assertEquals("test", ((Table1)result.get(0)[1]).getCryptoString());
+        assertEquals(1, result.get(0)[2]);
+        assertEquals(2, result.get(0)[3]);
+        assertEquals("string", result.get(0)[4]);
     }
 
     @Test